diff --git a/composer.json b/composer.json index 54a09143d..2e1202d21 100644 --- a/composer.json +++ b/composer.json @@ -3,38 +3,119 @@ "description": "Write and deploy modern PHP 8 code, today.", "type": "composer-plugin", "require": { - "php": ">=8.0", - "phabel/php-parser": "^94.10", + "php": ">=5.6 <5.7", + "ext-json": "*", "composer-plugin-api": "^2.0", - "symfony/console": "^5", - "symfony/process": "^5", - "amphp/parallel": "^1.4", - "psr/log": "^1.0", - "ext-json": "*" + "ext-tokenizer": "*" }, "require-dev": { "composer/composer": "^1|^2", "haydenpierce/class-finder": "^0.4.2", - "symfony/polyfill-php80": "^1.23", - "symfony/polyfill-php70": "*", - "symfony/polyfill-php71": "*", - "symfony/polyfill-php72": "*", - "symfony/polyfill-php73": "*", - "symfony/polyfill-php74": "*", "bamarni/composer-bin-plugin": "^1.4" }, "provide": { "phabelio/phabel": "self.version" }, "license": "MIT", - "authors": [{ - "name": "Daniil Gentili", - "email": "daniil@daniil.it" - }], + "authors": [ + { + "name": "Daniil Gentili", + "email": "daniil@daniil.it" + } + ], "autoload": { "psr-4": { - "Phabel\\": "src" - } + "Phabel\\": "src", + "Phabel\\Amp\\": [ + "vendor-bundle/amphp/amp/lib" + ], + "Phabel\\Amp\\ByteStream\\": [ + "vendor-bundle/amphp/byte-stream/lib" + ], + "Phabel\\Amp\\Parallel\\": [ + "vendor-bundle/amphp/parallel/lib" + ], + "Phabel\\Amp\\Parser\\": [ + "vendor-bundle/amphp/parser/lib" + ], + "Phabel\\Amp\\Process\\": [ + "vendor-bundle/amphp/process/lib" + ], + "Phabel\\Amp\\Serialization\\": [ + "vendor-bundle/amphp/serialization/src" + ], + "Phabel\\Amp\\Sync\\": [ + "vendor-bundle/amphp/sync/src" + ], + "Phabel\\PhpParser\\": [ + "vendor-bundle/phabel/php-parser/lib/PhpParser" + ], + "Phabel\\Psr\\Container\\": [ + "vendor-bundle/psr/container/src/" + ], + "Phabel\\Psr\\Log\\": [ + "vendor-bundle/psr/log/Psr/Log/" + ], + "Phabel\\Symfony\\Component\\Console\\": [ + "vendor-bundle/symfony/console/" + ], + "Phabel\\Symfony\\Polyfill\\Ctype\\": [ + "vendor-bundle/symfony/polyfill-ctype/" + ], + "Phabel\\Symfony\\Polyfill\\Intl\\Grapheme\\": [ + "vendor-bundle/symfony/polyfill-intl-grapheme/" + ], + "Phabel\\Symfony\\Polyfill\\Intl\\Normalizer\\": [ + "vendor-bundle/symfony/polyfill-intl-normalizer/" + ], + "Phabel\\Symfony\\Polyfill\\Mbstring\\": [ + "vendor-bundle/symfony/polyfill-mbstring/" + ], + "Phabel\\Symfony\\Polyfill\\Php72\\": [ + "vendor-bundle/symfony/polyfill-php72/" + ], + "Phabel\\Symfony\\Polyfill\\Php73\\": [ + "vendor-bundle/symfony/polyfill-php73/" + ], + "Phabel\\Symfony\\Polyfill\\Php74\\": [ + "vendor-bundle/symfony/polyfill-php74/" + ], + "Phabel\\Symfony\\Polyfill\\Php80\\": [ + "vendor-bundle/symfony/polyfill-php80/" + ], + "Phabel\\Symfony\\Component\\Process\\": [ + "vendor-bundle/symfony/process/" + ], + "Phabel\\Symfony\\Contracts\\Service\\": [ + "vendor-bundle/symfony/service-contracts/" + ], + "Phabel\\Symfony\\Component\\String\\": [ + "vendor-bundle/symfony/string/" + ] + }, + "files": [ + "vendor-bundle/amphp/amp/lib/functions.php", + "vendor-bundle/amphp/amp/lib/Internal/functions.php", + "vendor-bundle/amphp/byte-stream/lib/functions.php", + "vendor-bundle/amphp/parallel/lib/Context/functions.php", + "vendor-bundle/amphp/parallel/lib/Sync/functions.php", + "vendor-bundle/amphp/parallel/lib/Worker/functions.php", + "vendor-bundle/amphp/process/lib/functions.php", + "vendor-bundle/amphp/serialization/src/functions.php", + "vendor-bundle/amphp/sync/src/functions.php", + "vendor-bundle/amphp/sync/src/ConcurrentIterator/functions.php", + "vendor-bundle/ralouphie/getallheaders/src/getallheaders.php", + "vendor-bundle/symfony/deprecation-contracts/function.php", + "vendor-bundle/symfony/polyfill-ctype/bootstrap.php", + "vendor-bundle/symfony/polyfill-intl-grapheme/bootstrap.php", + "vendor-bundle/symfony/polyfill-intl-normalizer/bootstrap.php", + "vendor-bundle/symfony/polyfill-mbstring/bootstrap.php", + "vendor-bundle/symfony/polyfill-php72/bootstrap.php", + "vendor-bundle/symfony/polyfill-php73/bootstrap.php", + "vendor-bundle/symfony/polyfill-php74/bootstrap.php", + "vendor-bundle/symfony/polyfill-php80/bootstrap.php", + "vendor-bundle/symfony/string/Resources/functions.php" + ] }, "autoload-dev": { "psr-4": { @@ -76,5 +157,7 @@ "config": { "process-timeout": 0 }, - "bin": ["bin/phabel"] -} + "bin": [ + "bin/phabel" + ] +} \ No newline at end of file diff --git a/scoper.inc.php b/scoper.inc.php index 8e1355bc0..77a661419 100644 --- a/scoper.inc.php +++ b/scoper.inc.php @@ -1,43 +1,19 @@ 'Phabel', - // By default when running php-scoper add-prefix, it will prefix all relevant code found in the current working // directory. You can however define which files should be scoped by defining a collection of Finders in the // following configuration key. // // For more see: https://github.com/humbug/php-scoper#finders-and-paths - 'finders' => [ - Finder::create()->files()->in('src'), - Finder::create() - ->files() - ->ignoreVCS(true) - ->notName('/LICENSE|.*\\.md|.*\\.dist|Makefile|composer\\.json|composer\\.lock/') - ->exclude([ - 'doc', - 'test', - 'test_old', - 'tests', - 'Tests', - 'vendor-bin', - ]) - ->in('vendor'), - Finder::create()->append([ - 'composer.json', - ]), - ], - + 'finders' => [Finder::create()->files()->in('src'), Finder::create()->files()->ignoreVCS(true)->notName('/LICENSE|.*\\.md|.*\\.dist|Makefile|composer\\.json|composer\\.lock/')->exclude(['doc', 'test', 'test_old', 'tests', 'Tests', 'vendor-bin'])->in('vendor'), Finder::create()->append(['composer.json'])], // Whitelists a list of files. Unlike the other whitelist related features, this one is about completely leaving // a file untouched. // Paths are relative to the configuration file unless if they are already absolute 'files-whitelist' => [], - // When scoping PHP files, there will be scenarios where some of the code being scoped indirectly references the // original namespace. These will include, for example, strings or string manipulations. PHP-Scoper has limited // support for prefixing such strings. To circumvent that, you can define patchers to manipulate the file to your @@ -45,7 +21,6 @@ // // For more see: https://github.com/humbug/php-scoper#patchers 'patchers' => [], - // PHP-Scoper's goal is to make sure that all code for a project lies in a distinct PHP namespace. However, you // may want to share a common API between the bundled code of your PHAR and the consumer code. For example if // you have a PHPUnit PHAR with isolated code, you still want the PHAR to be able to understand the @@ -55,23 +30,17 @@ // that this does not work with functions or constants neither with classes belonging to the global namespace. // // Fore more see https://github.com/humbug/php-scoper#whitelist - 'whitelist' => [ - 'Phabel\*', - 'Composer\*', - ], - + 'whitelist' => ['Phabel\\*', 'Composer\\*'], // If `true` then the user defined constants belonging to the global namespace will not be prefixed. // // For more see https://github.com/humbug/php-scoper#constants--constants--functions-from-the-global-namespace 'whitelist-global-constants' => true, - // If `true` then the user defined classes belonging to the global namespace will not be prefixed. // // For more see https://github.com/humbug/php-scoper#constants--constants--functions-from-the-global-namespace 'whitelist-global-classes' => true, - // If `true` then the user defined functions belonging to the global namespace will not be prefixed. // // For more see https://github.com/humbug/php-scoper#constants--constants--functions-from-the-global-namespace 'whitelist-global-functions' => true, -]; +]; \ No newline at end of file diff --git a/src/ClassStorage.php b/src/ClassStorage.php index 1475cbd7d..ac73902a9 100644 --- a/src/ClassStorage.php +++ b/src/ClassStorage.php @@ -5,35 +5,31 @@ use Phabel\ClassStorage\Storage; use Phabel\Plugin\ClassStoragePlugin; use Phabel\Plugin\TypeHintReplacer; -use PhpParser\Node\Identifier; -use PhpParser\Node\Name; -use PhpParser\Node\NullableType; -use PhpParser\Node\UnionType; - +use Phabel\PhpParser\Node\Identifier; +use Phabel\PhpParser\Node\Name; +use Phabel\PhpParser\Node\NullableType; +use Phabel\PhpParser\Node\UnionType; final class ClassStorage { const FILE_KEY = 'ClassStorage:file'; - /** * Classes. * * @var array> */ - private array $classes = []; + private $classes = []; /** * Traits. * * @var array> */ - private array $traits = []; - + private $traits = []; /** * Files to process. * * @var array */ - private array $files = []; - + private $files = []; /** * Constructor. */ @@ -49,33 +45,34 @@ public function __construct(ClassStoragePlugin $plugin) $class->resolve($plugin); } } - foreach ($plugin->traits as $name => $fileTraits) { foreach ($fileTraits as $file => $trait) { $trait = $trait->build(); $this->traits[$name][$file] = $trait; - $this->files[$file] = true; + $this->files[$file] = \true; } } foreach ($plugin->classes as $name => $fileClasses) { foreach ($fileClasses as $file => $class) { $class = $class->build(); $this->classes[$name][$file] = $class; - $this->files[$file] = true; + $this->files[$file] = \true; } } } - /** * Get all files to process. * * @return array */ - public function getFiles(): array + public function getFiles() { - return $this->files; + $phabelReturn = $this->files; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Get class. * @@ -84,9 +81,25 @@ public function getFiles(): array * * @return Storage */ - public function getClass(string $file, string $name): Storage + public function getClass($file, $name) { - return $this->classes[$name][$file] ?? $this->traits[$name][$file]; + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($file) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $file = (string) $file; + } + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $name = (string) $name; + } + $phabelReturn = isset($this->classes[$name][$file]) ? $this->classes[$name][$file] : $this->traits[$name][$file]; + if (!$phabelReturn instanceof Storage) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Storage, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Get class by class name. @@ -95,27 +108,38 @@ public function getClass(string $file, string $name): Storage * * @return ?Storage */ - public function getClassByName(string $class): ?Storage + public function getClassByName($class) { - return \array_values($this->classes[$class] ?? [])[0] ?? null; + if (!\is_string($class)) { + if (!(\is_string($class) || \is_object($class) && \method_exists($class, '__toString') || (\is_bool($class) || \is_numeric($class)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($class) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($class) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $class = (string) $class; + } + $phabelReturn = null !== ($phabel_18d10d89847cd942 = \array_values(isset($this->classes[$class]) ? $this->classes[$class] : [])) && isset($phabel_18d10d89847cd942[0]) ? $phabel_18d10d89847cd942[0] : null; + if (!($phabelReturn instanceof Storage || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Storage, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Get storage. * * @return \Generator */ - public function getClasses(): \Generator + public function getClasses() { foreach ($this->classes as $class => $classes) { foreach ($classes as $_ => $storage) { - yield $class => $storage; + (yield $class => $storage); } } } - - private static function typeArray(null|Identifier|Name|NullableType|UnionType $type): array + private static function typeArray($type) { + if (!(\is_null($type) || $type instanceof Identifier || $type instanceof Name || $type instanceof NullableType || $type instanceof UnionType)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($type) must be of type Identifier|Name|NullableType|UnionType|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } $types = []; if ($type instanceof NullableType) { $types = [$type->type, new Identifier('null')]; @@ -124,7 +148,11 @@ private static function typeArray(null|Identifier|Name|NullableType|UnionType $t } elseif (!TypeHintReplacer::replaced($type)) { $types = [$type]; } - return $types; + $phabelReturn = $types; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Compare two types. @@ -136,32 +164,63 @@ private static function typeArray(null|Identifier|Name|NullableType|UnionType $t * * @return integer */ - public function compare(null|Identifier|Name|NullableType|UnionType $typeA, null|Identifier|Name|NullableType|UnionType $typeB, Storage $ctxA, Storage $ctxB): int + public function compare($typeA, $typeB, Storage $ctxA, Storage $ctxB) { + if (!(\is_null($typeA) || $typeA instanceof Identifier || $typeA instanceof Name || $typeA instanceof NullableType || $typeA instanceof UnionType)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($typeA) must be of type Identifier|Name|NullableType|UnionType|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($typeA) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!(\is_null($typeB) || $typeB instanceof Identifier || $typeB instanceof Name || $typeB instanceof NullableType || $typeB instanceof UnionType)) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($typeB) must be of type Identifier|Name|NullableType|UnionType|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($typeB) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } $typeA = self::typeArray($typeA); $typeB = self::typeArray($typeB); if (\count($typeA) !== \count($typeB)) { - return \count($typeA) <=> \count($typeB); + $phabelReturn = \Phabel\Target\Php70\SpaceshipOperatorReplacer::spaceship(\count($typeA), \count($typeB)); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } if (\count($typeA) + \count($typeB) === 2) { $typeA = $typeA[0]; $typeB = $typeB[0]; - if ($typeA instanceof Name && $typeB instanceof Name - && ($classA = $typeA->parts === ['self'] ? $ctxA : $this->getClassByName(Tools::getFqdn($typeA))) - && ($classB = $typeA->parts === ['self'] ? $ctxB : $this->getClassByName(Tools::getFqdn($typeB))) - ) { + if ($typeA instanceof Name && $typeB instanceof Name && ($classA = $typeA->parts === ['self'] ? $ctxA : $this->getClassByName(\Phabel\Tools::getFqdn($typeA))) && ($classB = $typeA->parts === ['self'] ? $ctxB : $this->getClassByName(\Phabel\Tools::getFqdn($typeB)))) { foreach ($classA->getAllChildren() as $child) { if ($child === $classB) { - return 1; + $phabelReturn = 1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } } foreach ($classB->getAllChildren() as $child) { if ($child === $classA) { - return -1; + $phabelReturn = -1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } } } } - return 0; + $phabelReturn = 0; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } } diff --git a/src/ClassStorage/Builder.php b/src/ClassStorage/Builder.php index 4d9edd845..823c264d3 100644 --- a/src/ClassStorage/Builder.php +++ b/src/ClassStorage/Builder.php @@ -6,16 +6,15 @@ use Phabel\Plugin\ClassStoragePlugin; use Phabel\PluginGraph\CircularException; use Phabel\Tools; -use PhpParser\Node\Stmt\Class_ as StmtClass_; -use PhpParser\Node\Stmt\ClassLike; -use PhpParser\Node\Stmt\ClassMethod; -use PhpParser\Node\Stmt\Interface_; -use PhpParser\Node\Stmt\TraitUse; -use PhpParser\Node\Stmt\TraitUseAdaptation\Alias; -use PhpParser\Node\Stmt\TraitUseAdaptation\Precedence; +use Phabel\PhpParser\Node\Stmt\Class_ as StmtClass_; +use Phabel\PhpParser\Node\Stmt\ClassLike; +use Phabel\PhpParser\Node\Stmt\ClassMethod; +use Phabel\PhpParser\Node\Stmt\Interface_; +use Phabel\PhpParser\Node\Stmt\TraitUse; +use Phabel\PhpParser\Node\Stmt\TraitUseAdaptation\Alias; +use Phabel\PhpParser\Node\Stmt\TraitUseAdaptation\Precedence; use RecursiveArrayIterator; use RecursiveIteratorIterator; - /** * Builds information about a class. */ @@ -27,27 +26,25 @@ class Builder * * @psalm-var array */ - private array $methods = []; + private $methods = []; /** * Abstract method list. * * @psalm-var array */ - private array $abstractMethods = []; - + private $abstractMethods = []; /** * Extended classes/interfaces. * * @var array */ - private array $extended = []; + private $extended = []; /** * Used classes/interfaces. * * @var array */ - private array $use = []; - + private $use = []; /** * Use aliases. * @@ -55,45 +52,43 @@ class Builder * * @var array> */ - private array $useAlias = []; - + private $useAlias = []; /** * Whether we're resolving. */ - private bool $resolving = false; + private $resolving = \false; /** * Whether we resolved. */ - private bool $resolved = false; - + private $resolved = \false; /** * Storage. */ - private ?Storage $storage = null; - + private $storage = null; /** * Class name. */ - private string $name; - + private $name; /** * Constructor. * * @param ClassLike $class Class or trait */ - public function __construct(ClassLike $class, string $customName = '') + public function __construct(ClassLike $class, $customName = '') { + if (!\is_string($customName)) { + if (!(\is_string($customName) || \is_object($customName) && \method_exists($customName, '__toString') || (\is_bool($customName) || \is_numeric($customName)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($customName) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($customName) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $customName = (string) $customName; + } $this->name = Tools::getFqdn($class, $customName); if ($class instanceof Interface_ || $class instanceof StmtClass_) { - foreach ( - \is_array($class->extends) - ? $class->extends - : ($class->extends ? [$class->extends] : []) - as $name) { - $this->extended[Tools::getFqdn($name)] = true; + foreach (\is_array($class->extends) ? $class->extends : ($class->extends ? [$class->extends] : []) as $name) { + $this->extended[Tools::getFqdn($name)] = \true; } - foreach ($class->implements ?? [] as $name) { - $this->extended[Tools::getFqdn($name)] = true; + foreach (isset($class->implements) ? $class->implements : [] as $name) { + $this->extended[Tools::getFqdn($name)] = \true; } } foreach ($class->stmts as $stmt) { @@ -102,23 +97,17 @@ public function __construct(ClassLike $class, string $customName = '') } if ($stmt instanceof TraitUse) { foreach ($stmt->traits as $trait) { - $this->use[Tools::getFqdn($trait)] = true; + $this->use[Tools::getFqdn($trait)] = \true; } foreach ($stmt->adaptations as $adapt) { $trait = Tools::getFqdn($adapt->trait); $method = Tools::getFqdn($adapt->method); if ($adapt instanceof Alias) { - $this->useAlias[$trait][$method] = [ - $trait, - Tools::getFqdn($adapt->newName) - ]; + $this->useAlias[$trait][$method] = [$trait, Tools::getFqdn($adapt->newName)]; } elseif ($adapt instanceof Precedence) { foreach ($adapt->insteadof as $name) { $insteadOf = Tools::getFqdn($name); - $this->useAlias[$insteadOf][$method] = [ - $trait, - $method - ]; + $this->useAlias[$insteadOf][$method] = [$trait, $method]; } } } @@ -139,26 +128,29 @@ private function addMethod(ClassMethod $method) $this->methods[$method->name->name] = $method; } } - /** * Resolve class tree. */ - public function resolve(ClassStoragePlugin $plugin): self + public function resolve(ClassStoragePlugin $plugin) { if ($this->resolved) { - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } if ($this->resolving) { $plugins = [$this->name]; - foreach (\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, DEBUG_BACKTRACE_PROVIDE_OBJECT) as $frame) { - $plugins []= $frame['object']->name; + foreach (\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, \DEBUG_BACKTRACE_PROVIDE_OBJECT) as $frame) { + $plugins[] = $frame['object']->name; if ($frame['object'] === $this) { break; } } throw new CircularException($plugins); } - $this->resolving = true; + $this->resolving = \true; foreach ($this->use as $trait => $_) { if (!isset($plugin->traits[$trait])) { continue; @@ -166,7 +158,7 @@ public function resolve(ClassStoragePlugin $plugin): self $resolved = \array_values($plugin->traits[$trait])[0]->resolve($plugin); foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator([$resolved->methods, $resolved->abstractMethods])) as $name => $method) { if (isset($this->useAlias[$trait][$name])) { - [$newTrait, $name] = $this->useAlias[$trait][$name]; + list($newTrait, $name) = $this->useAlias[$trait][$name]; if (!isset($plugin->traits[$newTrait])) { continue; } @@ -192,41 +184,43 @@ public function resolve(ClassStoragePlugin $plugin): self unset($this->extended[$class]); } } - $this->resolving = false; - $this->resolved = true; - - return $this; + $this->resolving = \false; + $this->resolved = \true; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Build storage. * * @return Storage */ - public function build(): Storage + public function build() { if (!$this->resolved) { throw new Exception("Trying to build an unresolved class!"); } if (!isset($this->storage)) { - $this->storage = new Storage; + $this->storage = new \Phabel\ClassStorage\Storage(); $this->storage->build($this->name, $this->methods, $this->abstractMethods, $this->extended); } - return $this->storage; + $phabelReturn = $this->storage; + if (!$phabelReturn instanceof \Phabel\ClassStorage\Storage) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Storage, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Debug info. */ - public function __debugInfo(): array + public function __debugInfo() { - return [ - 'name' => $this->name, - 'methods' => \array_keys($this->methods), - 'abstractMethods' => \array_keys($this->abstractMethods), - 'extended' => $this->extended, - 'useAlias' => $this->useAlias, - 'use' => $this->use, - ]; + $phabelReturn = ['name' => $this->name, 'methods' => \array_keys($this->methods), 'abstractMethods' => \array_keys($this->abstractMethods), 'extended' => $this->extended, 'useAlias' => $this->useAlias, 'use' => $this->use]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/ClassStorage/Storage.php b/src/ClassStorage/Storage.php index cffe28ea4..1e1d36581 100644 --- a/src/ClassStorage/Storage.php +++ b/src/ClassStorage/Storage.php @@ -2,55 +2,49 @@ namespace Phabel\ClassStorage; -use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\ClassMethod; - +use Phabel\PhpParser\Node\Stmt\Class_; +use Phabel\PhpParser\Node\Stmt\ClassMethod; /** * Stores information about a class. */ class Storage { - private const MODIFIER_NORMAL = 256; + const MODIFIER_NORMAL = 256; const STORAGE_KEY = 'Storage:instance'; /** * Method list. * * @psalm-var array */ - private array $methods = []; + private $methods = []; /** * Abstract method list. * * @psalm-var array */ - private array $abstractMethods = []; - + private $abstractMethods = []; /** * Removed method list. * * @var array */ - private array $removedMethods = []; - + private $removedMethods = []; /** * Classes/interfaces to extend. * * @var array */ - private array $extends = []; - + private $extends = []; /** * Classes/interfaces that extend us. * * @var array */ - private array $extendedBy = []; - + private $extendedBy = []; /** * Class name. */ - private string $name; - + private $name; /** * Constructor. * @@ -59,26 +53,30 @@ class Storage * @param array $abstractMethods * @param array $extends */ - public function build(string $name, array $methods, array $abstractMethods, array $extends) + public function build($name, array $methods, array $abstractMethods, array $extends) { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $name = (string) $name; + } $this->name = $name; $this->methods = $methods; $this->abstractMethods = $abstractMethods; - foreach ($methods as $method) { - if ($method->getAttribute(Builder::STORAGE_KEY)) { - $method->setAttribute(self::STORAGE_KEY, $method->getAttribute(Builder::STORAGE_KEY)->build()); - $method->setAttribute(Builder::STORAGE_KEY, null); + if ($method->getAttribute(\Phabel\ClassStorage\Builder::STORAGE_KEY)) { + $method->setAttribute(self::STORAGE_KEY, $method->getAttribute(\Phabel\ClassStorage\Builder::STORAGE_KEY)->build()); + $method->setAttribute(\Phabel\ClassStorage\Builder::STORAGE_KEY, null); } $method->flags |= self::MODIFIER_NORMAL; } foreach ($abstractMethods as $method) { - if ($method->getAttribute(Builder::STORAGE_KEY)) { - $method->setAttribute(self::STORAGE_KEY, $method->getAttribute(Builder::STORAGE_KEY)->build()); - $method->setAttribute(Builder::STORAGE_KEY, null); + if ($method->getAttribute(\Phabel\ClassStorage\Builder::STORAGE_KEY)) { + $method->setAttribute(self::STORAGE_KEY, $method->getAttribute(\Phabel\ClassStorage\Builder::STORAGE_KEY)->build()); + $method->setAttribute(\Phabel\ClassStorage\Builder::STORAGE_KEY, null); } } - foreach ($extends as $name => $class) { $this->extends[$name] = $class->build(); } @@ -86,17 +84,22 @@ public function build(string $name, array $methods, array $abstractMethods, arra $class->extendedBy[$this->name] = $this; } } - /** * Get name. * * @return string */ - public function getName(): string + public function getName() { - return $this->name; + $phabelReturn = $this->name; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - /** * Get method list. * @@ -105,70 +108,85 @@ public function getName(): string * * @return \Generator */ - public function getMethods(int $typeMask = ~Class_::VISIBILITY_MODIFIER_MASK, int $visibilityMask = Class_::VISIBILITY_MODIFIER_MASK): \Generator + public function getMethods($typeMask = ~Class_::VISIBILITY_MODIFIER_MASK, $visibilityMask = Class_::VISIBILITY_MODIFIER_MASK) { + if (!\is_int($typeMask)) { + if (!(\is_bool($typeMask) || \is_numeric($typeMask))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($typeMask) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($typeMask) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $typeMask = (int) $typeMask; + } + if (!\is_int($visibilityMask)) { + if (!(\is_bool($visibilityMask) || \is_numeric($visibilityMask))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($visibilityMask) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($visibilityMask) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $visibilityMask = (int) $visibilityMask; + } if ($typeMask & Class_::MODIFIER_ABSTRACT) { foreach ($this->abstractMethods as $name => $method) { - if (($method->flags|Class_::MODIFIER_ABSTRACT) & $typeMask && $method->flags & $visibilityMask) { - yield $name => $method; + if (($method->flags | Class_::MODIFIER_ABSTRACT) & $typeMask && $method->flags & $visibilityMask) { + (yield $name => $method); } } } if ($typeMask & self::MODIFIER_NORMAL) { foreach ($this->methods as $name => $method) { if ($method->flags & $typeMask && $method->flags & $visibilityMask) { - yield $name => $method; + (yield $name => $method); } } } } - /** * Get classes which extend this class. * * @return array */ - public function getExtendedBy(): array + public function getExtendedBy() { - return $this->extendedBy; + $phabelReturn = $this->extendedBy; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Get classes which this class extends. * * @return array */ - public function getExtends(): array + public function getExtends() { - return $this->extends; + $phabelReturn = $this->extends; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Get all child classes. * * @return \Generator */ - public function getAllChildren(): \Generator + public function getAllChildren() { foreach ($this->extendedBy as $class) { - yield $class; + (yield $class); yield from $class->getAllChildren(); } } - /** * Get all parent classes. * * @return \Generator */ - public function getAllParents(): \Generator + public function getAllParents() { foreach ($this->extends as $class) { - yield $class; + (yield $class); yield from $class->getAllParents(); } } - /** * Get all methods which override the specified method in child classes. * @@ -178,26 +196,43 @@ public function getAllParents(): \Generator * * @return \Generator */ - public function getOverriddenMethods(string $name, int $typeMask = ~Class_::VISIBILITY_MODIFIER_MASK, int $visibilityMask = Class_::VISIBILITY_MODIFIER_MASK): \Generator + public function getOverriddenMethods($name, $typeMask = ~Class_::VISIBILITY_MODIFIER_MASK, $visibilityMask = Class_::VISIBILITY_MODIFIER_MASK) { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $name = (string) $name; + } + if (!\is_int($typeMask)) { + if (!(\is_bool($typeMask) || \is_numeric($typeMask))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($typeMask) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($typeMask) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $typeMask = (int) $typeMask; + } + if (!\is_int($visibilityMask)) { + if (!(\is_bool($visibilityMask) || \is_numeric($visibilityMask))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($visibilityMask) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($visibilityMask) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $visibilityMask = (int) $visibilityMask; + } foreach ($this->getAllChildren() as $child) { if (isset($child->abstractMethods[$name])) { $method = $child->abstractMethods[$name]; $flags = $method->flags | Class_::MODIFIER_ABSTRACT; if ($flags & $typeMask && $flags & $visibilityMask) { - yield $method; + (yield $method); } } if (isset($child->methods[$name])) { $method = $child->methods[$name]; $flags = $method->flags; if ($flags & $typeMask && $flags & $visibilityMask) { - yield $method; + (yield $method); } } } } - /** * Remove method. * @@ -205,36 +240,62 @@ public function getOverriddenMethods(string $name, int $typeMask = ~Class_::VISI * * @return bool */ - public function removeMethod(ClassMethod $method): bool + public function removeMethod(ClassMethod $method) { $name = $method->name->name; if ($method->stmts !== null) { if (isset($this->methods[$name])) { - $this->removedMethods[$name] = true; + $this->removedMethods[$name] = \true; unset($this->methods[$name]); - return true; + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } } elseif (isset($this->abstractMethods[$name])) { - $this->removedMethods[$name] = true; + $this->removedMethods[$name] = \true; unset($this->abstractMethods[$name]); - return true; + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - - return false; + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - /** * Process method from AST. * * @return bool */ - public function process(ClassMethod $method): bool + public function process(ClassMethod $method) { $name = $method->name->name; if (isset($this->removedMethods[$name])) { - return true; + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - $myMethod = $this->methods[$name] ?? $this->abstractMethods[$name]; + $myMethod = isset($this->methods[$name]) ? $this->methods[$name] : $this->abstractMethods[$name]; foreach ($myMethod->getSubNodeNames() as $name) { if ($name === 'stmts') { continue; @@ -246,6 +307,13 @@ public function process(ClassMethod $method): bool $method->setAttribute($key, $attribute); } } - return false; + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } } diff --git a/src/ClassStorageProvider.php b/src/ClassStorageProvider.php index 7b40a6c62..8ffcd78cf 100644 --- a/src/ClassStorageProvider.php +++ b/src/ClassStorageProvider.php @@ -4,32 +4,30 @@ use JsonSerializable; use Phabel\ClassStorage\Storage; -use PhpParser\Node\Stmt\ClassLike; -use PhpParser\Node\Stmt\ClassMethod; -use PhpParser\Node\Stmt\Nop; - -abstract class ClassStorageProvider extends Plugin implements JsonSerializable +use Phabel\PhpParser\Node\Stmt\ClassLike; +use Phabel\PhpParser\Node\Stmt\ClassMethod; +use Phabel\PhpParser\Node\Stmt\Nop; +abstract class ClassStorageProvider extends \Phabel\Plugin implements JsonSerializable { - private const PROCESSED = 'ClassStorageProvider:processed'; + const PROCESSED = 'ClassStorageProvider:processed'; /** * Class count. */ - private array $count = []; - + private $count = []; /** * Process class graph. * * @param ClassStorage $storage * @return bool */ - abstract public static function processClassGraph(ClassStorage $storage): bool; + public static abstract function processClassGraph(\Phabel\ClassStorage $storage); /** * Enter file. * * @param RootNode $_ * @return void */ - public function enterRoot(RootNode $_, Context $context): void + public function enterRoot(\Phabel\RootNode $_, \Phabel\Context $context) { $this->count[$context->getFile()] = []; } @@ -39,20 +37,19 @@ public function enterRoot(RootNode $_, Context $context): void * @param ClassLike $classLike * @return void */ - public function enterClassStorage(ClassLike $class, Context $context): void + public function enterClassStorage(ClassLike $class, \Phabel\Context $context) { if ($class->hasAttribute(self::PROCESSED)) { return; } - $class->setAttribute(self::PROCESSED, true); - + $class->setAttribute(self::PROCESSED, \true); $file = $context->getFile(); if ($class->name) { $name = self::getFqdn($class); } else { - $name = "class@anonymous$file"; - $this->count[$file][$name] ??= 0; - $name .= "@".$this->count[$file][$name]++; + $name = "class@anonymous{$file}"; + $this->count[$file][$name] = isset($this->count[$file][$name]) ? $this->count[$file][$name] : 0; + $name .= "@" . $this->count[$file][$name]++; } $storage = $this->getGlobalClassStorage()->getClass($file, $name); foreach ($class->stmts as $k => $stmt) { @@ -66,17 +63,28 @@ public function enterClassStorage(ClassLike $class, Context $context): void * * @return ClassStorage */ - public function getGlobalClassStorage(): ClassStorage + public function getGlobalClassStorage() { - return $this->getConfig(ClassStorage::class, null); + $phabelReturn = $this->getConfig(\Phabel\ClassStorage::class, null); + if (!$phabelReturn instanceof \Phabel\ClassStorage) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ClassStorage, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * JSON representation. * * @return string */ - public function jsonSerialize(): string + public function jsonSerialize() { - return \spl_object_hash($this); + $phabelReturn = \spl_object_hash($this); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } } diff --git a/src/Cli/EventHandler.php b/src/Cli/EventHandler.php index 0f7d70b95..eebc00819 100644 --- a/src/Cli/EventHandler.php +++ b/src/Cli/EventHandler.php @@ -3,113 +3,172 @@ namespace Phabel\Cli; use Phabel\EventHandler as PhabelEventHandler; -use Psr\Log\LoggerInterface; -use Symfony\Component\Console\Formatter\OutputFormatter; -use Symfony\Component\Console\Helper\ProgressBar; -use Symfony\Component\Console\Output\ConsoleOutput; -use Throwable; - +use Phabel\Psr\Log\LoggerInterface; +use Phabel\Symfony\Component\Console\Helper\ProgressBar; +use Phabel\Symfony\Component\Console\Output\ConsoleOutput; class EventHandler extends PhabelEventHandler { - private OutputFormatter $outputFormatter; - private ?ProgressBar $progress = null; + private $outputFormatter; + private $progress = null; /** * Progress bar getter. * * @var null|(callable(int): ProgressBar) */ private $getProgressBar = null; - private int $count = 0; + private $count = 0; /** * Create simple CLI-based preconfigured instance. * * @return self */ - public static function create(): self + public static function create() { $output = new ConsoleOutput(); - return new EventHandler( - new SimpleConsoleLogger($output), - fn (int $max): ProgressBar => new ProgressBar($output, $max, -1) - ); + $phabelReturn = new \Phabel\Cli\EventHandler(new \Phabel\Cli\SimpleConsoleLogger($output), function ($max) use($output) { + if (!\is_int($max)) { + if (!(\is_bool($max) || \is_numeric($max))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($max) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($max) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $max = (int) $max; + } + $phabelReturn = new ProgressBar($output, $max, -1); + if (!$phabelReturn instanceof ProgressBar) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ProgressBar, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + }); + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public function __construct(private LoggerInterface $logger, ?callable $getProgressBar) + public function __construct(private LoggerInterface $logger, $getProgressBar) { - $this->outputFormatter = Formatter::getFormatter(); + if (!(\is_callable($getProgressBar) || \is_null($getProgressBar))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($getProgressBar) must be of type ?callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($getProgressBar) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $this->outputFormatter = \Phabel\Cli\Formatter::getFormatter(); $this->getProgressBar = $getProgressBar; } - public function onBeginPluginGraphResolution(): void + public function onBeginPluginGraphResolution() { $this->logger->debug($this->outputFormatter->format("Plugin graph resolution in progress...")); } - public function onEndPluginGraphResolution(): void + public function onEndPluginGraphResolution() { $this->logger->debug($this->outputFormatter->format("Finished plugin graph resolution!")); } - - private function startProgressBar(string $message, int $total, int $workers = 1): void + private function startProgressBar($message, $total, $workers = 1) { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $message = (string) $message; + } + if (!\is_int($total)) { + if (!(\is_bool($total) || \is_numeric($total))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($total) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($total) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $total = (int) $total; + } + if (!\is_int($workers)) { + if (!(\is_bool($workers) || \is_numeric($workers))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($workers) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($workers) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $workers = (int) $workers; + } if ($this->getProgressBar) { - $this->progress = ($this->getProgressBar)($total); + $phabel_11f8432a35865732 = $this->getProgressBar; + $this->progress = $phabel_11f8432a35865732($total); $this->progress->setFormat($this->outputFormatter->format('%message% %percent:3s%% (%current%/%max%)')); } if ($this->progress) { if ($workers > 1) { - $message .= " ($workers threads)"; + $message .= " ({$workers} threads)"; } $this->progress->setMessage($message); $this->progress->clear(); $this->progress->start(); } else { - $this->logger->debug($this->outputFormatter->format("$message")); + $this->logger->debug($this->outputFormatter->format("{$message}")); } } - - public function onBeginDirectoryTraversal(int $total, int $workers): void + public function onBeginDirectoryTraversal($total, $workers) { + if (!\is_int($total)) { + if (!(\is_bool($total) || \is_numeric($total))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($total) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($total) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $total = (int) $total; + } + if (!\is_int($workers)) { + if (!(\is_bool($workers) || \is_numeric($workers))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($workers) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($workers) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $workers = (int) $workers; + } if (!$this->count) { $message = 'Transpilation in progress...'; } else { $secondary = $this->count === 1 ? 'covariance and contravariance' : 'further covariance and contravariance'; - $message = "Applying $secondary transforms..."; + $message = "Applying {$secondary} transforms..."; } $this->count++; $this->startProgressBar($message, $total, $workers); } - public function onEndAstTraversal(string $file, int|\Throwable $iterationsOrError): void + public function onEndAstTraversal($file, $iterationsOrError) { - $this->progress?->advance(); - if ($iterationsOrError instanceof Throwable) { - $this->logger->error($this->outputFormatter->format(PHP_EOL."{$iterationsOrError->getMessage()}!")); - $this->logger->debug($this->outputFormatter->format("$iterationsOrError")); + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($file) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $file = (string) $file; + } + if (!($iterationsOrError instanceof \Exception || $iterationsOrError instanceof \Error)) { + if (!\is_int($iterationsOrError)) { + if (!(\is_bool($iterationsOrError) || \is_numeric($iterationsOrError))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($iterationsOrError) must be of type Throwable|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($iterationsOrError) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $iterationsOrError = (int) $iterationsOrError; + } + } + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->progress) ? $this->progress : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->advance(); + if ($iterationsOrError instanceof \Exception || $iterationsOrError instanceof \Error) { + $this->logger->error($this->outputFormatter->format(\PHP_EOL . "{$iterationsOrError->getMessage()}!")); + $this->logger->debug($this->outputFormatter->format("{$iterationsOrError}")); } else { - $this->logger->debug($this->outputFormatter->format("Transpiled $file in $iterationsOrError iterations!")); + $this->logger->debug($this->outputFormatter->format("Transpiled {$file} in {$iterationsOrError} iterations!")); } } - public function onEndDirectoryTraversal(): void + public function onEndDirectoryTraversal() { - $this->progress?->finish(); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->progress) ? $this->progress : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->finish(); $this->logger->warning(""); } - - public function onBeginClassGraphMerge(int $count): void + public function onBeginClassGraphMerge($count) { + if (!\is_int($count)) { + if (!(\is_bool($count) || \is_numeric($count))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($count) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($count) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $count = (int) $count; + } $this->startProgressBar("Merging class graphs...", $count); } - public function onClassGraphMerged(): void + public function onClassGraphMerged() { - $this->progress?->advance(); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->progress) ? $this->progress : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->advance(); $this->logger->debug($this->outputFormatter->format("Merged class graph!")); } - public function onEndClassGraphMerge(): void + public function onEndClassGraphMerge() { - $this->progress?->finish(); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->progress) ? $this->progress : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->finish(); } - - public function onEnd(): void + public function onEnd() { - $this->progress?->clear(); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->progress) ? $this->progress : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->clear(); $this->logger->warning($this->outputFormatter->format('Done!')); } } diff --git a/src/Cli/Formatter.php b/src/Cli/Formatter.php index f88147820..8843125cb 100644 --- a/src/Cli/Formatter.php +++ b/src/Cli/Formatter.php @@ -2,31 +2,32 @@ namespace Phabel\Cli; -use Symfony\Component\Console\Formatter\OutputFormatter; -use Symfony\Component\Console\Formatter\OutputFormatterStyle; - +use Phabel\Symfony\Component\Console\Formatter\OutputFormatter; +use Phabel\Symfony\Component\Console\Formatter\OutputFormatterStyle; class Formatter { - public const BANNER = "********* - Phabel -********* - -PHP transpiler - Write and deploy modern PHP 8 code, today: https://phabel.io"; - - private static ?OutputFormatter $instance = null; - public static function getFormatter(): OutputFormatter + const BANNER = "*********\n Phabel \n*********\n\nPHP transpiler - Write and deploy modern PHP 8 code, today: https://phabel.io"; + private static $instance = null; + public static function getFormatter() { if (!self::$instance) { - self::$instance = new OutputFormatter(true, [ - 'bold' => new OutputFormatterStyle('white', 'default', ['bold']), - 'phabel' => new OutputFormatterStyle('blue', 'default', ['bold']), - 'error' => new OutputFormatterStyle('red', 'default', ['bold']) - ]); + self::$instance = new OutputFormatter(\true, ['bold' => new OutputFormatterStyle('white', 'default', ['bold']), 'phabel' => new OutputFormatterStyle('blue', 'default', ['bold']), 'error' => new OutputFormatterStyle('red', 'default', ['bold'])]); } - return self::$instance; + $phabelReturn = self::$instance; + if (!$phabelReturn instanceof OutputFormatter) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type OutputFormatter, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - public static function banner(): string + public static function banner() { - return self::getFormatter()->format(self::BANNER); + $phabelReturn = self::getFormatter()->format(self::BANNER); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } } diff --git a/src/Cli/SimpleConsoleLogger.php b/src/Cli/SimpleConsoleLogger.php index ae003007a..655909824 100644 --- a/src/Cli/SimpleConsoleLogger.php +++ b/src/Cli/SimpleConsoleLogger.php @@ -8,15 +8,13 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Phabel\Cli; -use Psr\Log\AbstractLogger; -use Psr\Log\InvalidArgumentException; -use Psr\Log\LogLevel; -use Symfony\Component\Console\Output\ConsoleOutputInterface; -use Symfony\Component\Console\Output\OutputInterface; - +use Phabel\Psr\Log\AbstractLogger; +use Phabel\Psr\Log\InvalidArgumentException; +use Phabel\Psr\Log\LogLevel; +use Phabel\Symfony\Component\Console\Output\ConsoleOutputInterface; +use Phabel\Symfony\Component\Console\Output\OutputInterface; /** * PSR-3 compliant console logger. * @@ -26,39 +24,18 @@ */ class SimpleConsoleLogger extends AbstractLogger { - public const INFO = 'info'; - public const ERROR = 'error'; - + const INFO = 'info'; + const ERROR = 'error'; private $output; - private $verbosityLevelMap = [ - LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, - LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, - LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL, - LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL, - LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL, - LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE, - LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE, - LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG, - ]; - private $formatLevelMap = [ - LogLevel::EMERGENCY => self::ERROR, - LogLevel::ALERT => self::ERROR, - LogLevel::CRITICAL => self::ERROR, - LogLevel::ERROR => self::ERROR, - LogLevel::WARNING => self::INFO, - LogLevel::NOTICE => self::INFO, - LogLevel::INFO => self::INFO, - LogLevel::DEBUG => self::INFO, - ]; - private $errored = false; - + private $verbosityLevelMap = [LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL, LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL, LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL, LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE, LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE, LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG]; + private $formatLevelMap = [LogLevel::EMERGENCY => self::ERROR, LogLevel::ALERT => self::ERROR, LogLevel::CRITICAL => self::ERROR, LogLevel::ERROR => self::ERROR, LogLevel::WARNING => self::INFO, LogLevel::NOTICE => self::INFO, LogLevel::INFO => self::INFO, LogLevel::DEBUG => self::INFO]; + private $errored = \false; public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = []) { $this->output = $output; $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap; $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap; } - /** * {@inheritdoc} * @@ -69,24 +46,20 @@ public function log($level, $message, array $context = []) if (!isset($this->verbosityLevelMap[$level])) { throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $level)); } - $output = $this->output; - // Write to the error output if necessary and available if (self::ERROR === $this->formatLevelMap[$level]) { if ($this->output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } - $this->errored = true; + $this->errored = \true; } - // the if condition check isn't necessary -- it's the same one that $output will do internally anyway. // We only do it for efficiency here as the message formatting is relatively expensive. if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { $output->writeln(\sprintf('<%1$s>%3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); } } - /** * Returns true when any messages have been logged at error levels. * @@ -96,31 +69,48 @@ public function hasErrored() { return $this->errored; } - /** * Interpolates context values into the message placeholders. * * @author PHP Framework Interoperability Group */ - private function interpolate(string $message, array $context): string + private function interpolate($message, array $context) { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $message = (string) $message; + } if (!\str_contains($message, '{')) { - return $message; + $phabelReturn = $message; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - $replacements = []; foreach ($context as $key => $val) { - if (null === $val || \is_scalar($val) || (\is_object($val) && \method_exists($val, '__toString'))) { + if (null === $val || \is_scalar($val) || \is_object($val) && \method_exists($val, '__toString')) { $replacements["{{$key}}"] = $val; } elseif ($val instanceof \DateTimeInterface) { $replacements["{{$key}}"] = $val->format(\DateTime::RFC3339); } elseif (\is_object($val)) { - $replacements["{{$key}}"] = '[object '.\get_class($val).']'; + $replacements["{{$key}}"] = '[object ' . \get_class($val) . ']'; } else { - $replacements["{{$key}}"] = '['.\gettype($val).']'; + $replacements["{{$key}}"] = '[' . \gettype($val) . ']'; } } - - return \strtr($message, $replacements); + $phabelReturn = \strtr($message, $replacements); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } } diff --git a/src/Commands/Publish.php b/src/Commands/Publish.php index 277defaf6..76adb54a6 100644 --- a/src/Commands/Publish.php +++ b/src/Commands/Publish.php @@ -6,34 +6,56 @@ use Phabel\Cli\Formatter; use Phabel\Plugin\ComposerSanitizer; use Phabel\Version; -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Process\Exception\ProcessFailedException; -use Symfony\Component\Process\Process; - +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Input\InputArgument; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Input\InputOption; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +use Phabel\Symfony\Component\Process\Exception\ProcessFailedException; +use Phabel\Symfony\Component\Process\Process; class Publish extends Command { protected static $defaultName = 'publish'; - - private function exec(array $command, bool $ignoreResult = false): string + private function exec(array $command, $ignoreResult = \false) { + if (!\is_bool($ignoreResult)) { + if (!(\is_bool($ignoreResult) || \is_numeric($ignoreResult) || \is_string($ignoreResult))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($ignoreResult) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($ignoreResult) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $ignoreResult = (bool) $ignoreResult; + } $proc = new Process($command); $proc->run(); if (!$proc->isSuccessful() && !$ignoreResult) { throw new ProcessFailedException($proc); } - return $proc->getOutput(); + $phabelReturn = $proc->getOutput(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - - private function getMessage(string $ref): string + private function getMessage($ref) { - return $this->exec(['git', 'log', '--format=%B', '-n', '1', $ref]); + if (!\is_string($ref)) { + if (!(\is_string($ref) || \is_object($ref) && \method_exists($ref, '__toString') || (\is_bool($ref) || \is_numeric($ref)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($ref) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($ref) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $ref = (string) $ref; + } + $phabelReturn = $this->exec(['git', 'log', '--format=%B', '-n', '1', $ref]); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - - protected function configure(): void + protected function configure() { $tags = new Process(['git', 'tag']); $tags->run(); @@ -44,77 +66,73 @@ protected function configure(): void break; } } - - $this - ->setDescription('Transpile a release.') - ->setHelp('This command transpiles the specified (or the latest) git tag.') - - ->addOption("remote", 'r', InputOption::VALUE_OPTIONAL, 'Remote where to push tags', 'origin') - ->addArgument('source', $tag ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'Source tag name', $tag); + $this->setDescription('Transpile a release.')->setHelp('This command transpiles the specified (or the latest) git tag.')->addOption("remote", 'r', InputOption::VALUE_OPTIONAL, 'Remote where to push tags', 'origin')->addArgument('source', $tag ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'Source tag name', $tag); } - - private function prepare(string $src, string $dest, callable $cb): void + private function prepare($src, $dest, callable $cb) { + if (!\is_string($src)) { + if (!(\is_string($src) || \is_object($src) && \method_exists($src, '__toString') || (\is_bool($src) || \is_numeric($src)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($src) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($src) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $src = (string) $src; + } + if (!\is_string($dest)) { + if (!(\is_string($dest) || \is_object($dest) && \method_exists($dest, '__toString') || (\is_bool($dest) || \is_numeric($dest)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($dest) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($dest) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $dest = (string) $dest; + } $this->exec(['git', 'checkout', $src]); $message = $this->getMessage($src); - if (!\file_exists('composer.json')) { throw new Exception("composer.json doesn't exist!"); } - - $json = \json_decode(\file_get_contents('composer.json'), true); + $json = \json_decode(\file_get_contents('composer.json'), \true); $json = $cb($json); - \file_put_contents('composer.json', \json_encode($json, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)); - - $this->exec(['git', 'commit', '-am', $message."\nRelease transpiled using https://phabel.io, the PHP transpiler"]); - $this->exec(['git', 'tag', '-d', $dest], true); + \file_put_contents('composer.json', \json_encode($json, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES)); + $this->exec(['git', 'commit', '-am', $message . "\nRelease transpiled using https://phabel.io, the PHP transpiler"]); + $this->exec(['git', 'tag', '-d', $dest], \true); $this->exec(['git', 'tag', $dest]); } - protected function execute(InputInterface $input, OutputInterface $output) { $src = $input->getArgument('source'); $remote = $input->getOption('remote'); $output->setFormatter(Formatter::getFormatter()); - $branch = \trim($this->exec(["git", 'rev-parse', '--abbrev-ref', 'HEAD'])); $stashed = \trim($this->exec(['git', 'stash'])) !== 'No local changes to save'; - - $output->write("Tagging transpiled release $src.9998...".PHP_EOL); - $this->prepare($src, "$src.9998", function (array $json): array { - $json['phabel'] ??= []; - $json['phabel']['extra'] ??= []; + $output->write("Tagging transpiled release {$src}.9998..." . \PHP_EOL); + $this->prepare($src, "{$src}.9998", function (array $json) { + $json['phabel'] = isset($json['phabel']) ? $json['phabel'] : []; + $json['phabel']['extra'] = isset($json['phabel']['extra']) ? $json['phabel']['extra'] : []; $json['phabel']['extra']['require'] = $json['require']; - $json['require'] = [ - 'phabel/phabel' => Version::VERSION, - 'php' => $json['require']['php'] - ]; - \file_put_contents(ComposerSanitizer::FILE_NAME, ComposerSanitizer::getContents($json['name'] ?? 'phabel')); + $json['require'] = ['phabel/phabel' => Version::VERSION, 'php' => $json['require']['php']]; + \file_put_contents(ComposerSanitizer::FILE_NAME, ComposerSanitizer::getContents(isset($json['name']) ? $json['name'] : 'phabel')); $this->exec(['git', 'add', ComposerSanitizer::FILE_NAME]); - $json['autoload'] ??= []; - $json['autoload']['files'] ??= []; - $json['autoload']['files'] []= ComposerSanitizer::FILE_NAME; - return $json; + $json['autoload'] = isset($json['autoload']) ? $json['autoload'] : []; + $json['autoload']['files'] = isset($json['autoload']['files']) ? $json['autoload']['files'] : []; + $json['autoload']['files'][] = ComposerSanitizer::FILE_NAME; + $phabelReturn = $json; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + }); + $output->write("Tagging original release as {$src}.9999..." . \PHP_EOL); + $this->prepare($src, "{$src}.9999", function (array $json) { + $phabelReturn = $json; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; }); - - $output->write("Tagging original release as $src.9999...".PHP_EOL); - $this->prepare($src, "$src.9999", fn (array $json): array => $json); - $this->exec(['git', 'checkout', $branch]); if ($stashed) { $this->exec(['git', 'stash', 'pop']); } - - $output->write("Pushing $src.9998, $src.9999 to $remote...".PHP_EOL); - $this->exec(['git', 'push', $remote, "$src.9998", "$src.9999"]); - - $output->write("Done! -Tell users to require ^$src in their composer.json to automatically load the correct transpiled version! - -Tip: Add the following badge to your README to let users know about your minimum supported PHP version, as it won't be shown on packagist. -![phabel.io](https://phabel.io/badge/5.6) -"); - + $output->write("Pushing {$src}.9998, {$src}.9999 to {$remote}..." . \PHP_EOL); + $this->exec(['git', 'push', $remote, "{$src}.9998", "{$src}.9999"]); + $output->write("Done!\nTell users to require ^{$src} in their composer.json to automatically load the correct transpiled version!\n\nTip: Add the following badge to your README to let users know about your minimum supported PHP version, as it won't be shown on packagist.\n![phabel.io](https://phabel.io/badge/5.6)\n"); return Command::SUCCESS; } } diff --git a/src/Commands/Run.php b/src/Commands/Run.php index f1f2256ff..6de78ab2e 100644 --- a/src/Commands/Run.php +++ b/src/Commands/Run.php @@ -7,70 +7,51 @@ use Phabel\Cli\SimpleConsoleLogger; use Phabel\Target\Php; use Phabel\Traverser; -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Helper\ProgressBar; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; - +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Helper\ProgressBar; +use Phabel\Symfony\Component\Console\Input\InputArgument; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Input\InputOption; +use Phabel\Symfony\Component\Console\Output\OutputInterface; class Run extends Command { protected static $defaultName = 'run'; - - protected function configure(): void + protected function configure() { $target = \getenv('PHABEL_TARGET') ?: null; - $coverage = \getenv('PHABEL_COVERAGE') ?: false; + $coverage = \getenv('PHABEL_COVERAGE') ?: \false; $parallel = \getenv('PHABEL_PARALLEL') ?: 1; - - $this - ->setDescription('Run transpiler.') - ->setHelp('This command transpiles the specified files or directories to the specified PHP version.') - - ->addOption('target', null, $target ? InputOption::VALUE_OPTIONAL : InputOption::VALUE_REQUIRED, 'Target PHP version', $target) - ->addOption('coverage', null, InputOption::VALUE_OPTIONAL, 'PHP coverage path', $coverage) - ->addOption('parallel', 'j', InputOption::VALUE_OPTIONAL, 'Number of threads to use for transpilation', $parallel) - - ->addArgument('input', InputArgument::REQUIRED, 'Input path') - ->addArgument('output', InputArgument::REQUIRED, 'Output path'); + $this->setDescription('Run transpiler.')->setHelp('This command transpiles the specified files or directories to the specified PHP version.')->addOption('target', null, $target ? InputOption::VALUE_OPTIONAL : InputOption::VALUE_REQUIRED, 'Target PHP version', $target)->addOption('coverage', null, InputOption::VALUE_OPTIONAL, 'PHP coverage path', $coverage)->addOption('parallel', 'j', InputOption::VALUE_OPTIONAL, 'Number of threads to use for transpilation', $parallel)->addArgument('input', InputArgument::REQUIRED, 'Input path')->addArgument('output', InputArgument::REQUIRED, 'Output path'); } - - protected function execute(InputInterface $input, OutputInterface $output) { $output->setFormatter(Formatter::getFormatter()); - $output->write(PHP_EOL.Formatter::BANNER.PHP_EOL.PHP_EOL); - + $output->write(\PHP_EOL . Formatter::BANNER . \PHP_EOL . \PHP_EOL); if (!$input->getOption('target')) { - $output->write("Missing --target parameter or PHABEL_TARGET environment variable!".PHP_EOL.PHP_EOL); + $output->write("Missing --target parameter or PHABEL_TARGET environment variable!" . \PHP_EOL . \PHP_EOL); return Command::INVALID; } - - $packages = (new Traverser( - new CliEventHandler( - new SimpleConsoleLogger($output), - !\getenv('CI') - && !$output->isDebug() ? fn (int $max): ProgressBar => new ProgressBar($output, $max, -1) : null - ) - )) - ->setPlugins([ - Php::class => ['target' => Php::normalizeVersion($input->getOption('target'))] - ]) - ->setInput($input->getArgument('input')) - ->setOutput($input->getArgument('output')) - ->setCoverage($input->getOption('coverage') ?: '') - ->run($input->getOption('parallel')); - + $packages = (new Traverser(new CliEventHandler(new SimpleConsoleLogger($output), !\getenv('CI') && !$output->isDebug() ? function ($max) use($output) { + if (!\is_int($max)) { + if (!(\is_bool($max) || \is_numeric($max))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($max) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($max) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $max = (int) $max; + } + $phabelReturn = new ProgressBar($output, $max, -1); + if (!$phabelReturn instanceof ProgressBar) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ProgressBar, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } : null)))->setPlugins([Php::class => ['target' => Php::normalizeVersion($input->getOption('target'))]])->setInput($input->getArgument('input'))->setOutput($input->getArgument('output'))->setCoverage($input->getOption('coverage') ?: '')->run($input->getOption('parallel')); if (!empty($packages)) { $cmd = "composer require --dev "; foreach ($packages as $package => $constraint) { - $cmd .= \escapeshellarg("$package:$constraint")." "; + $cmd .= \escapeshellarg("{$package}:{$constraint}") . " "; } - $output->write("Please run the following command to install required development dependencies:".PHP_EOL); - $output->write($cmd.PHP_EOL); + $output->write("Please run the following command to install required development dependencies:" . \PHP_EOL); + $output->write($cmd . \PHP_EOL); } - return Command::SUCCESS; } } diff --git a/src/Composer/Plugin.php b/src/Composer/Plugin.php index c2ad14941..21f04b9d6 100644 --- a/src/Composer/Plugin.php +++ b/src/Composer/Plugin.php @@ -13,19 +13,18 @@ use Composer\Script\ScriptEvents; use Phabel\Tools; use Phabel\Version; -use Symfony\Component\Console\Input\ArrayInput; -use Symfony\Component\Console\Output\NullOutput; - +use Phabel\Symfony\Component\Console\Input\ArrayInput; +use Phabel\Symfony\Component\Console\Output\NullOutput; /** * @author Daniil Gentili * @license MIT */ class Plugin implements PluginInterface, EventSubscriberInterface { - private string $toRequire = ''; + private $toRequire = ''; /** @psalm-suppress MissingConstructor */ - private Transformer $transformer; - private ?array $lock = null; + private $transformer; + private $lock = null; /** * Apply plugin modifications to Composer. * @@ -34,14 +33,13 @@ class Plugin implements PluginInterface, EventSubscriberInterface * * @return void */ - public function activate(Composer $composer, IOInterface $io): void + public function activate(Composer $composer, IOInterface $io) { if (\file_exists('composer.lock')) { - $this->lock = \json_decode(\file_get_contents('composer.lock'), true); + $this->lock = \json_decode(\file_get_contents('composer.lock'), \true); } - $rootPackage = $composer->getPackage(); - $this->transformer = Transformer::getInstance($io); + $this->transformer = \Phabel\Composer\Transformer::getInstance($io); $this->transformer->preparePackage($rootPackage, $rootPackage->getName()); foreach ($rootPackage->getRequires() as $link) { if (PlatformRepository::isPlatformPackage($link->getTarget())) { @@ -49,18 +47,16 @@ public function activate(Composer $composer, IOInterface $io): void } $this->toRequire = $link->getTarget(); } - $repoManager = $composer->getRepositoryManager(); $repos = $repoManager->getRepositories(); foreach (\array_reverse($repos) as $repo) { if (!\method_exists($repo, 'setPhabelTransformer')) { - $repo = Tools::cloneWithTrait($repo, Repository::class); + $repo = Tools::cloneWithTrait($repo, \Phabel\Composer\Repository::class); $repo->setPhabelTransformer($this->transformer); $repoManager->prependRepository($repo); } } } - /** * Remove any hooks from Composer. * @@ -74,7 +70,6 @@ public function activate(Composer $composer, IOInterface $io): void public function deactivate(Composer $composer, IOInterface $io) { } - /** * Prepare the plugin to be uninstalled. * @@ -86,61 +81,58 @@ public function deactivate(Composer $composer, IOInterface $io) public function uninstall(Composer $composer, IOInterface $io) { } - /** * {@inheritdoc} */ public static function getSubscribedEvents() { - return [ - ScriptEvents::POST_INSTALL_CMD => - ['onInstall', 1], - ScriptEvents::POST_UPDATE_CMD => - ['onUpdate', 1] - ]; + return [ScriptEvents::POST_INSTALL_CMD => ['onInstall', 1], ScriptEvents::POST_UPDATE_CMD => ['onUpdate', 1]]; } - - public function onInstall(Event $event): void + public function onInstall(Event $event) { - $this->run($event, false); + $this->run($event, \false); } - public function onUpdate(Event $event): void + public function onUpdate(Event $event) { - $this->run($event, true); + $this->run($event, \true); } - private function run(Event $event, bool $isUpdate): void + private function run(Event $event, $isUpdate) { - $lock = \json_decode(\file_get_contents('composer.lock'), true); + if (!\is_bool($isUpdate)) { + if (!(\is_bool($isUpdate) || \is_numeric($isUpdate) || \is_string($isUpdate))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($isUpdate) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($isUpdate) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $isUpdate = (bool) $isUpdate; + } + $lock = \json_decode(\file_get_contents('composer.lock'), \true); if (!$this->transformer->transform($lock, $this->lock)) { - \register_shutdown_function(function () use ($isUpdate) { + \register_shutdown_function(function () use($isUpdate) { /** @var Application */ - $application = ($GLOBALS['application'] ?? null) instanceof Application ? $GLOBALS['application'] : new Application; + $application = (isset($GLOBALS['application']) ? $GLOBALS['application'] : null) instanceof Application ? $GLOBALS['application'] : new Application(); $this->transformer->log("Loading additional dependencies...\n"); if (!$isUpdate) { $require = $application->find('require'); - $require->run(new ArrayInput(['packages' => [$this->toRequire]]), new NullOutput); + $require->run(new ArrayInput(['packages' => [$this->toRequire]]), new NullOutput()); } else { - $application->setAutoExit(false); + $application->setAutoExit(\false); $application->run(); } }); } else { \register_shutdown_function(function () { - $json = \json_decode(\file_get_contents('composer.json'), true); + $json = \json_decode(\file_get_contents('composer.json'), \true); if (!isset($json['require']['phabel/phabel'])) { return; } - $old = $json['extra']['phabel']['revision'] ?? -1; + $old = isset($json['extra']['phabel']['revision']) ? $json['extra']['phabel']['revision'] : -1; if ($old === Version::LATEST) { return; } - $json['extra'] ??= []; - $json['extra']['phabel'] ??= []; + $json['extra'] = isset($json['extra']) ? $json['extra'] : []; + $json['extra']['phabel'] = isset($json['extra']['phabel']) ? $json['extra']['phabel'] : []; $json['extra']['phabel']['revision'] = Version::LATEST; - - $json['require'] ??= []; + $json['require'] = isset($json['require']) ? $json['require'] : []; $json['require']['php'] = '^8.0'; - $this->transformer->banner(); $f = [$this->transformer, 'format']; $io = $this->transformer->getIo(); @@ -149,13 +141,10 @@ private function run(Event $event, bool $isUpdate): void $io->writeError($f(Version::CHANGELOG[$x])); } } - - \file_put_contents('composer.json', \json_encode($json, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES).PHP_EOL); + \file_put_contents('composer.json', \json_encode($json, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES) . \PHP_EOL); }); } } - - /** * Emitted before composer solves dependencies. * @@ -163,7 +152,7 @@ private function run(Event $event, bool $isUpdate): void * * @return void */ - public function onDependencySolve(InstallerEvent $event): void + public function onDependencySolve(InstallerEvent $event) { } } diff --git a/src/Composer/Repository.php b/src/Composer/Repository.php index d6b0e4a3c..35c47da8b 100644 --- a/src/Composer/Repository.php +++ b/src/Composer/Repository.php @@ -3,14 +3,13 @@ namespace Phabel\Composer; use Composer\Package\PackageInterface; - /** * @author Daniil Gentili * @license MIT */ trait Repository { - private Transformer $phabelTransformer; + private $phabelTransformer; /** * TODO v3 should make this private once we can drop PHP 5.3 support. * @@ -19,7 +18,7 @@ trait Repository */ public function isVersionAcceptable($constraint, $name, $versionData, array $acceptableStabilities = null, array $stabilityFlags = null) { - [$name] = $this->phabelTransformer->extractTarget($name); + list($name) = $this->phabelTransformer->extractTarget($name); return parent::isVersionAcceptable($constraint, $name, $versionData, $acceptableStabilities, $stabilityFlags); } /** @@ -37,44 +36,41 @@ public function loadPackages(array $packageNameMap, array $acceptableStabilities $newPackageNameMap = []; $transformInfo = []; foreach ($packageNameMap as $key => $constraint) { - [$package, $target] = $this->phabelTransformer->extractTarget($key); - $newPackageNameMap[$target] ??= []; + list($package, $target) = $this->phabelTransformer->extractTarget($key); + $newPackageNameMap[$target] = isset($newPackageNameMap[$target]) ? $newPackageNameMap[$target] : []; $newPackageNameMap[$target][$package] = $constraint; - $transformInfo[$target] ??= []; + $transformInfo[$target] = isset($transformInfo[$target]) ? $transformInfo[$target] : []; $transformInfo[$target][$package] = $key; } foreach ($alreadyLoaded as $key => $versions) { - [$package, $target] = $this->phabelTransformer->extractTarget($key); - $newAlreadyLoaded[$target] ??= []; + list($package, $target) = $this->phabelTransformer->extractTarget($key); + $newAlreadyLoaded[$target] = isset($newAlreadyLoaded[$target]) ? $newAlreadyLoaded[$target] : []; $newAlreadyLoaded[$target][$package] = $versions; } - $finalNamesFound = []; $finalPackages = []; foreach ($newPackageNameMap as $target => $map) { $t = $transformInfo[$target]; - $packages = parent::loadPackages($map, $acceptableStabilities, $stabilityFlags, $newAlreadyLoaded[$target] ?? []); + $packages = parent::loadPackages($map, $acceptableStabilities, $stabilityFlags, isset($newAlreadyLoaded[$target]) ? $newAlreadyLoaded[$target] : []); foreach ($packages['namesFound'] as $package) { - $finalNamesFound []= $t[$package]; + $finalNamesFound[] = $t[$package]; } foreach ($packages['packages'] as $package) { $package = clone $package; $this->phabelTransformer->preparePackage($package, $t[$package->getName()], $target); - $finalPackages []= $package; + $finalPackages[] = $package; } } $packages['namesFound'] = $finalNamesFound; $packages['packages'] = $finalPackages; - /*$missing = \array_diff(\array_keys($packageNameMap), $finalNamesFound); - if (!empty($missing)) { - $this->phabelTransformer->getIo()->debug("Could not find the following packages in ".\get_parent_class($this).": ".\implode(", ", $missing)); - } else { - $this->phabelTransformer->getIo()->debug("Loaded packages in ".\get_parent_class($this).": ".\implode(", ", $finalNamesFound)); - }*/ + if (!empty($missing)) { + $this->phabelTransformer->getIo()->debug("Could not find the following packages in ".\get_parent_class($this).": ".\implode(", ", $missing)); + } else { + $this->phabelTransformer->getIo()->debug("Loaded packages in ".\get_parent_class($this).": ".\implode(", ", $finalNamesFound)); + }*/ return $packages; } - /** * Searches for the first match of a package by name and version. * @@ -85,15 +81,14 @@ public function loadPackages(array $packageNameMap, array $acceptableStabilities */ public function findPackage($fullName, $constraint) { - [$name, $target] = $this->phabelTransformer->extractTarget($fullName); - if (!$package = parent::findPackage($name, $constraint)) { + list($name, $target) = $this->phabelTransformer->extractTarget($fullName); + if (!($package = parent::findPackage($name, $constraint))) { return null; } $package = clone $package; $this->phabelTransformer->preparePackage($package, $fullName, $target); return $package; } - /** * Searches for all packages matching a name and optionally a version. * @@ -104,7 +99,7 @@ public function findPackage($fullName, $constraint) */ public function findPackages($fullName, $constraint = null) { - [$name, $target] = $this->phabelTransformer->extractTarget($fullName); + list($name, $target) = $this->phabelTransformer->extractTarget($fullName); $packages = parent::findPackages($name, $constraint); foreach ($packages as &$package) { $package = clone $package; @@ -112,7 +107,6 @@ public function findPackages($fullName, $constraint = null) } return $packages; } - /** * Returns list of registered packages. * @@ -127,7 +121,6 @@ public function getPackages() } return $packages; } - /** * Set the Transformer. * @@ -135,10 +128,13 @@ public function getPackages() * * @return self */ - public function setPhabelTransformer(Transformer $phabelTransformer): self + public function setPhabelTransformer(\Phabel\Composer\Transformer $phabelTransformer) { $this->phabelTransformer = $phabelTransformer; - - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Composer/Transformer.php b/src/Composer/Transformer.php index d435446b6..b6abf50a9 100644 --- a/src/Composer/Transformer.php +++ b/src/Composer/Transformer.php @@ -20,9 +20,7 @@ use Phabel\Target\Php; use Phabel\Traverser; use ReflectionClass; -use Symfony\Component\Console\Formatter\OutputFormatter; -use Symfony\Component\Console\Helper\ProgressBar; - +use Phabel\Symfony\Component\Console\Helper\ProgressBar; class Transformer extends EventHandler { const HEADER = 'phabel/transpiler'; @@ -30,45 +28,48 @@ class Transformer extends EventHandler /** * IO interface. */ - private IOInterface $io; + private $io; /** * IO interface. */ - private OutputFormatter $outputFormatter; - + private $outputFormatter; /** * Version parser. */ - private VersionParser $versionParser; + private $versionParser; /** * Requires. */ - private array $requires = []; + private $requires = []; /** * Whether we processed requirements. */ - private array $processedRequires = []; + private $processedRequires = []; /** * Whether we processed any dependencies. */ - private bool $processed = false; + private $processed = \false; /** * Whether a progress bar should be shown. */ - private bool $doProgress = true; + private $doProgress = \true; /** * Instance. */ - private static self $instance; + private static $instance; /** * Get singleton. * * @return self */ - public static function getInstance(IOInterface $io): self + public static function getInstance(IOInterface $io) { - self::$instance ??= new self($io); - return self::$instance; + self::$instance = isset(self::$instance) ? self::$instance : new self($io); + $phabelReturn = self::$instance; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Constructor. @@ -78,11 +79,9 @@ public static function getInstance(IOInterface $io): self private function __construct(IOInterface $io) { $this->io = $io; - $this->versionParser = new VersionParser; - + $this->versionParser = new VersionParser(); $this->outputFormatter = Formatter::getFormatter(); } - /** * Log text. * @@ -91,36 +90,64 @@ private function __construct(IOInterface $io) * @param bool $newline * @return void */ - public function log(string $text, int $verbosity = IOInterface::NORMAL, bool $newline = true): void + public function log($text, $verbosity = IOInterface::NORMAL, $newline = \true) { - $this->io->writeError($this->format("$text"), $newline, $verbosity); + if (!\is_string($text)) { + if (!(\is_string($text) || \is_object($text) && \method_exists($text, '__toString') || (\is_bool($text) || \is_numeric($text)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($text) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($text) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $text = (string) $text; + } + if (!\is_int($verbosity)) { + if (!(\is_bool($verbosity) || \is_numeric($verbosity))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($verbosity) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($verbosity) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $verbosity = (int) $verbosity; + } + if (!\is_bool($newline)) { + if (!(\is_bool($newline) || \is_numeric($newline) || \is_string($newline))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($newline) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $newline = (bool) $newline; + } + $this->io->writeError($this->format("{$text}"), $newline, $verbosity); } - /** * Format text. * * @param string $text * @return string */ - public function format(string $text): string + public function format($text) { - return $this->outputFormatter->format($text); + if (!\is_string($text)) { + if (!(\is_string($text) || \is_object($text) && \method_exists($text, '__toString') || (\is_bool($text) || \is_numeric($text)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($text) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($text) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $text = (string) $text; + } + $phabelReturn = $this->outputFormatter->format($text); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - /** * Print banner. * * @return void */ - public function banner(): void + public function banner() { - static $printed = false; + static $printed = \false; if (!$printed) { - $printed = true; - $this->log(PHP_EOL.Formatter::BANNER.PHP_EOL); + $printed = \true; + $this->log(\PHP_EOL . Formatter::BANNER . \PHP_EOL); } } - /** * Prepare package for phabel tree injection. * @@ -130,19 +157,31 @@ public function banner(): void * * @return void */ - public function preparePackage(PackageInterface &$package, string $newName, int $target = Php::TARGET_IGNORE): void + public function preparePackage(PackageInterface &$package, $newName, $target = Php::TARGET_IGNORE) { + if (!\is_string($newName)) { + if (!(\is_string($newName) || \is_object($newName) && \method_exists($newName, '__toString') || (\is_bool($newName) || \is_numeric($newName)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($newName) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newName) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $newName = (string) $newName; + } + if (!\is_int($target)) { + if (!(\is_bool($target) || \is_numeric($target))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($target) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($target) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $target = (int) $target; + } /** * Phabel configuration of current package. * @var array */ - $config = $package->getExtra()['phabel'] ?? []; - $myTarget = Php::normalizeVersion($config['target'] ?? Php::DEFAULT_TARGET); - $havePhabel = false; + $config = null !== ($phabel_f0c212d00f8be226 = $package->getExtra()) && isset($phabel_f0c212d00f8be226['phabel']) ? $phabel_f0c212d00f8be226['phabel'] : []; + $myTarget = Php::normalizeVersion(isset($config['target']) ? $config['target'] : Php::DEFAULT_TARGET); + $havePhabel = \false; foreach ($package->getRequires() as $link) { - [$name] = $this->extractTarget($link->getTarget()); + list($name) = $this->extractTarget($link->getTarget()); if ($name === 'phabel/phabel') { - $havePhabel = true; + $havePhabel = \true; } if ($link->getTarget() === 'php') { $myTarget = $link->getConstraint()->getLowerBound()->getVersion(); @@ -151,10 +190,10 @@ public function preparePackage(PackageInterface &$package, string $newName, int } } } - $this->processed = true; + $this->processed = \true; if (!$havePhabel) { if ($target === Php::TARGET_IGNORE) { - $this->log("Skipping ".$package->getName()."=$newName", IOInterface::VERY_VERBOSE); + $this->log("Skipping " . $package->getName() . "={$newName}", IOInterface::VERY_VERBOSE); return; } $myTarget = $target; @@ -162,40 +201,20 @@ public function preparePackage(PackageInterface &$package, string $newName, int $myTarget = Php::normalizeVersion($myTarget); $myTarget = \min($myTarget, $target); } - - $this->log("Applying ".$package->getName()."=$newName", IOInterface::VERY_VERBOSE); - + $this->log("Applying " . $package->getName() . "={$newName}", IOInterface::VERY_VERBOSE); $this->processedRequires = $this->requires; $requires = $this->requires; - foreach ($config['require'] ?? [] as $name => $constraint) { + foreach (isset($config['require']) ? $config['require'] : [] as $name => $constraint) { $requires[$this->injectTarget($name, $myTarget)] = $constraint; } - if ($newName !== $package->getName() && \method_exists($package, 'setProvides')) { - $package->setProvides(\array_merge( - $package->getProvides(), - [$package->getName() => new Link( - $newName, - $package->getName(), - new ComposerConstraint('=', $package->getVersion()), - Link::TYPE_PROVIDE, - $package->getVersion() - )] - )); + $package->setProvides(\array_merge($package->getProvides(), [$package->getName() => new Link($newName, $package->getName(), new ComposerConstraint('=', $package->getVersion()), Link::TYPE_PROVIDE, $package->getVersion())])); } - $base = new ReflectionClass(BasePackage::class); $method = $base->getMethod('__construct'); $method->invokeArgs($package, [$newName]); - - $this->processRequires( - $package, - $myTarget, - $requires, - $havePhabel, - ); + $this->processRequires($package, $myTarget, $requires, $havePhabel); } - /** * Add phabel config to all requires. * @@ -206,44 +225,35 @@ public function preparePackage(PackageInterface &$package, string $newName, int * * @return void */ - private function processRequires(PackageInterface $package, int $target, array $requires, bool $havePhabel) + private function processRequires(PackageInterface $package, $target, array $requires, $havePhabel) { + if (!\is_int($target)) { + if (!(\is_bool($target) || \is_numeric($target))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($target) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($target) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $target = (int) $target; + } + if (!\is_bool($havePhabel)) { + if (!(\is_bool($havePhabel) || \is_numeric($havePhabel) || \is_string($havePhabel))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($havePhabel) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($havePhabel) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $havePhabel = (bool) $havePhabel; + } $links = []; foreach ($package->getRequires() as $name => $link) { if (PlatformRepository::isPlatformPackage($link->getTarget())) { if ($link->getTarget() === 'php') { - $constraint = MultiConstraint::create([ - new ComposerConstraint('>=', Php::unnormalizeVersion($target)), - new ComposerConstraint('<', Php::unnormalizeVersion($target+1)) - ]); - $links[$name]= new Link( - $package->getName(), - $link->getTarget(), - $constraint, - $link->getDescription(), - $constraint->getPrettyString() - ); + $constraint = MultiConstraint::create([new ComposerConstraint('>=', Php::unnormalizeVersion($target)), new ComposerConstraint('<', Php::unnormalizeVersion($target + 1))]); + $links[$name] = new Link($package->getName(), $link->getTarget(), $constraint, $link->getDescription(), $constraint->getPrettyString()); } else { $links[$name] = $link; } continue; } - $links [$name]= new Link( - $package->getName(), - $havePhabel ? $link->getTarget() : $this->injectTarget($link->getTarget(), $target), - $link->getConstraint(), - $link->getDescription(), - $link->getPrettyConstraint() - ); + $links[$name] = new Link($package->getName(), $havePhabel ? $link->getTarget() : $this->injectTarget($link->getTarget(), $target), $link->getConstraint(), $link->getDescription(), $link->getPrettyConstraint()); } foreach ($requires as $name => $version) { - $links[$name] = new Link( - $package->getName(), - $name, - $this->versionParser->parseConstraints($version), - Link::TYPE_REQUIRE, - $version - ); + $links[$name] = new Link($package->getName(), $name, $this->versionParser->parseConstraints($version), Link::TYPE_REQUIRE, $version); } if ($package instanceof Package) { $package->setRequires($links); @@ -251,7 +261,6 @@ private function processRequires(PackageInterface $package, int $target, array $ $this->processRequires($package->getAliasOf(), $target, $requires, $havePhabel); } } - /** * Inject target into package name. * @@ -259,12 +268,30 @@ private function processRequires(PackageInterface $package, int $target, array $ * @param int $target * @return string */ - private function injectTarget(string $package, int $target): string + private function injectTarget($package, $target) { - [$package] = $this->extractTarget($package); - return self::HEADER.$target.self::SEPARATOR.$package; + if (!\is_string($package)) { + if (!(\is_string($package) || \is_object($package) && \method_exists($package, '__toString') || (\is_bool($package) || \is_numeric($package)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($package) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($package) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $package = (string) $package; + } + if (!\is_int($target)) { + if (!(\is_bool($target) || \is_numeric($target))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($target) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($target) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $target = (int) $target; + } + list($package) = $this->extractTarget($package); + $phabelReturn = self::HEADER . $target . self::SEPARATOR . $package; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - /** * Look for phabel configuration parameters in constraint. * @@ -272,15 +299,28 @@ private function injectTarget(string $package, int $target): string * * @return array{0: string, 1: int} */ - public function extractTarget(string $package): array + public function extractTarget($package) { + if (!\is_string($package)) { + if (!(\is_string($package) || \is_object($package) && \method_exists($package, '__toString') || (\is_bool($package) || \is_numeric($package)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($package) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($package) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $package = (string) $package; + } if (\str_starts_with($package, self::HEADER)) { - [$version, $package] = \explode(self::SEPARATOR, \substr($package, \strlen(self::HEADER)), 2); - return [$package, $version]; + list($version, $package) = \explode(self::SEPARATOR, \substr($package, \strlen(self::HEADER)), 2); + $phabelReturn = [$package, $version]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = [$package, Php::TARGET_IGNORE]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return [$package, Php::TARGET_IGNORE]; + return $phabelReturn; } - /** * Transform dependencies. * @@ -288,48 +328,51 @@ public function extractTarget(string $package): array * @param ?array $old * @return bool Whether no more packages should be updated */ - public function transform(?array $lock, ?array $old): bool + public function transform($lock, $old) { + if (!(\is_array($lock) || \is_null($lock))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($lock) must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($lock) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!(\is_array($old) || \is_null($old))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($old) must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($old) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } $enabled = \gc_enabled(); \gc_enable(); - - $packages = $lock['packages'] ?? []; - + $packages = isset($lock['packages']) ? $lock['packages'] : []; $this->log("Creating plugin graph...", IOInterface::VERBOSE); $byName = []; foreach ($packages as $package) { - [$name, $target] = $this->extractTarget($package['name']); + list($name, $target) = $this->extractTarget($package['name']); if ($target === Php::TARGET_IGNORE) { continue; } $package['phabelTarget'] = (int) $target; - $package['phabelConfig'] = [$package['extra']['phabel'] ?? []]; + $package['phabelConfig'] = [isset($package['extra']['phabel']) ? $package['extra']['phabel'] : []]; unset($package['phabelConfig'][0]['target']); $byName[$name] = $package; } do { - $changed = false; + $changed = \false; foreach ($byName as $name => $package) { $parentConfigs = $package['phabelConfig']; - foreach ($package['require'] ?? [] as $subName => $constraint) { + foreach (isset($package['require']) ? $package['require'] : [] as $subName => $constraint) { if (PlatformRepository::isPlatformPackage($subName)) { continue; } - [$subName] = $this->extractTarget($subName); + list($subName) = $this->extractTarget($subName); if ($target === Php::TARGET_IGNORE) { continue; } foreach ($parentConfigs as $config) { if (!\in_array($config, $byName[$subName]['phabelConfig'])) { $byName[$subName]['phabelConfig'][] = $config; - $changed = true; + $changed = \true; } } } } } while ($changed); - - $graph = new Graph; + $graph = new Graph(); foreach ($byName as $name => $package) { $ctx = $graph->getPackageContext(); $ctx->addPackage($name); @@ -338,71 +381,118 @@ public function transform(?array $lock, ?array $old): bool $graph->addPlugin(Php::class, $config + $target, $ctx); } } - - $traverser = new Traverser( - new CliEventHandler( - $this->io, - $this->doProgress - && $this->io instanceof ConsoleIO - && !\getenv('CI') - && !$this->io->isDebug() ? fn (int $progress): ProgressBar => $this->io->getProgressBar($progress) : null - ) - ); + $traverser = new Traverser(new CliEventHandler($this->io, $this->doProgress && $this->io instanceof ConsoleIO && !\getenv('CI') && !$this->io->isDebug() ? function ($progress) { + if (!\is_int($progress)) { + if (!(\is_bool($progress) || \is_numeric($progress))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($progress) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($progress) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $progress = (int) $progress; + } + $phabelReturn = $this->io->getProgressBar($progress); + if (!$phabelReturn instanceof ProgressBar) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ProgressBar, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } : null)); $traverser->setPluginGraph($graph); unset($graph); - $this->requires = $traverser->getGraph()->getPackages(); if (!$this->processedRequires()) { if (!$enabled) { unset($traverser); - while (\gc_collect_cycles()); + while (\gc_collect_cycles()) { + } \gc_disable(); } - return false; + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } if ($lock && $lock === $old) { - return true; + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } if (!$byName) { - return true; + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - $this->banner(); - - $traverser - ->setInput('vendor') - ->setOutput('vendor') - ->setComposer(function (string $rel): string { - [$package] = $this->extractTarget(\str_replace('\\', '/', $rel)); - return \implode('/', \array_slice(\explode('/', $package), 0, 2)); - }) - ->run((int) (\getenv('PHABEL_PARALLEL') ?: 1)); - + $traverser->setInput('vendor')->setOutput('vendor')->setComposer(function ($rel) { + if (!\is_string($rel)) { + if (!(\is_string($rel) || \is_object($rel) && \method_exists($rel, '__toString') || (\is_bool($rel) || \is_numeric($rel)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($rel) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($rel) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $rel = (string) $rel; + } + list($package) = $this->extractTarget(\str_replace('\\', '/', $rel)); + $phabelReturn = \implode('/', \array_slice(\explode('/', $package), 0, 2)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; + })->run((int) (\getenv('PHABEL_PARALLEL') ?: 1)); if (!$enabled) { unset($traverser); - while (\gc_collect_cycles()); + while (\gc_collect_cycles()) { + } \gc_disable(); } - return true; + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - /** * Get whether we processed any dependencies. * * @return bool */ - public function processedRequires(): bool + public function processedRequires() { - return $this->processed && $this->processedRequires === $this->requires; + $phabelReturn = $this->processed && $this->processedRequires === $this->requires; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - /** * Get IO interface. * * @return IOInterface */ - public function getIo(): IOInterface + public function getIo() { - return $this->io; + $phabelReturn = $this->io; + if (!$phabelReturn instanceof IOInterface) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type IOInterface, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Context.php b/src/Context.php index 52e79ae51..49487f9f3 100644 --- a/src/Context.php +++ b/src/Context.php @@ -3,40 +3,38 @@ namespace Phabel; use Phabel\Target\Php74\ArrowClosure; -use PhpParser\BuilderHelpers; -use PhpParser\ErrorHandler\Throwing; -use PhpParser\NameContext; -use PhpParser\Node; -use PhpParser\Node\Expr\Array_; -use PhpParser\Node\Expr\ArrayDimFetch; -use PhpParser\Node\Expr\ArrowFunction; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\AssignOp; -use PhpParser\Node\Expr\AssignRef; -use PhpParser\Node\Expr\BinaryOp\BooleanAnd; -use PhpParser\Node\Expr\BinaryOp\BooleanOr; -use PhpParser\Node\Expr\BinaryOp\Coalesce; -use PhpParser\Node\Expr\BooleanNot; -use PhpParser\Node\Expr\Cast\Bool_; -use PhpParser\Node\Expr\Closure; -use PhpParser\Node\Expr\FuncCall; -use PhpParser\Node\Expr\List_; -use PhpParser\Node\Expr\MethodCall; -use PhpParser\Node\Expr\StaticCall; -use PhpParser\Node\Expr\Ternary; -use PhpParser\Node\Expr\Variable; -use PhpParser\Node\FunctionLike; -use PhpParser\Node\Name\FullyQualified; -use PhpParser\Node\Param; -use PhpParser\Node\Stmt\ClassLike; -use PhpParser\Node\Stmt\Else_; -use PhpParser\Node\Stmt\Expression; -use PhpParser\Node\Stmt\If_; -use PhpParser\NodeVisitor\NameResolver; -use PhpParser\PrettyPrinter\Standard; -use PhpParser\PrettyPrinterAbstract; +use Phabel\PhpParser\BuilderHelpers; +use Phabel\PhpParser\ErrorHandler\Throwing; +use Phabel\PhpParser\NameContext; +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Expr\Array_; +use Phabel\PhpParser\Node\Expr\ArrayDimFetch; +use Phabel\PhpParser\Node\Expr\ArrowFunction; +use Phabel\PhpParser\Node\Expr\Assign; +use Phabel\PhpParser\Node\Expr\AssignOp; +use Phabel\PhpParser\Node\Expr\AssignRef; +use Phabel\PhpParser\Node\Expr\BinaryOp\BooleanAnd; +use Phabel\PhpParser\Node\Expr\BinaryOp\BooleanOr; +use Phabel\PhpParser\Node\Expr\BinaryOp\Coalesce; +use Phabel\PhpParser\Node\Expr\BooleanNot; +use Phabel\PhpParser\Node\Expr\Cast\Bool_; +use Phabel\PhpParser\Node\Expr\Closure; +use Phabel\PhpParser\Node\Expr\FuncCall; +use Phabel\PhpParser\Node\Expr\List_; +use Phabel\PhpParser\Node\Expr\MethodCall; +use Phabel\PhpParser\Node\Expr\StaticCall; +use Phabel\PhpParser\Node\Expr\Ternary; +use Phabel\PhpParser\Node\Expr\Variable; +use Phabel\PhpParser\Node\FunctionLike; +use Phabel\PhpParser\Node\Name\FullyQualified; +use Phabel\PhpParser\Node\Param; +use Phabel\PhpParser\Node\Stmt\ClassLike; +use Phabel\PhpParser\Node\Stmt\Else_; +use Phabel\PhpParser\Node\Stmt\Expression; +use Phabel\PhpParser\Node\Stmt\If_; +use Phabel\PhpParser\NodeVisitor\NameResolver; +use Phabel\PhpParser\PrettyPrinter\Standard; use SplStack; - /** * AST Context. * @@ -50,57 +48,51 @@ class Context * * @var SplStack */ - public SplStack $parents; + public $parents; /** * Declared variables stack. * * @var SplStack */ - public SplStack $variables; + public $variables; /** * Name resolver. * * @var NameResolver */ - public NameResolver $nameResolver; + public $nameResolver; /** * Pretty printer. */ - public PrettyPrinterAbstract $prettyPrinter; + public $prettyPrinter; /** * Arrow closure converter. */ - private ArrowClosure $converter; + private $converter; /** * Current file. */ - private string $file; + private $file; /** * Current input file. */ - private string $inputFile; + private $inputFile; /** * Current output file. */ - private string $outputFile; + private $outputFile; /** * Constructor. */ public function __construct() { /** @var SplStack */ - $this->parents = new SplStack; + $this->parents = new SplStack(); /** @var SplStack */ - $this->variables = new SplStack; - $this->converter = new ArrowClosure; + $this->variables = new SplStack(); + $this->converter = new ArrowClosure(); $this->prettyPrinter = new Standard(); - $this->nameResolver = new NameResolver( - new Throwing, - [ - 'preserveOriginalNames' => false, - 'replaceNodes' => false, - ] - ); + $this->nameResolver = new NameResolver(new Throwing(), ['preserveOriginalNames' => \false, 'replaceNodes' => \false]); $this->nameResolver->beforeTraverse([]); } /** @@ -109,7 +101,7 @@ public function __construct() * @param Node $node * @return void */ - public function pushResolve(Node $node): void + public function pushResolve(Node $node) { if (!$node instanceof FullyQualified) { $this->nameResolver->enterNode($node); @@ -122,23 +114,26 @@ public function pushResolve(Node $node): void * * @return void */ - public function push(Node $node): void + public function push(Node $node) { $this->parents->push($node); - if ($node instanceof RootNode) { - $this->variables->push(new VariableContext); + if ($node instanceof \Phabel\RootNode) { + $this->variables->push(new \Phabel\VariableContext()); } if ($node instanceof FunctionLike) { - $variables = \array_fill_keys( - \array_map( - fn (Param $param): string => $param->var->name, - $node->getParams() - ), - true - ); + $variables = \array_fill_keys(\array_map(function (Param $param) { + $phabelReturn = $param->var->name; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; + }, $node->getParams()), \true); if ($node instanceof Closure) { foreach ($node->uses as $use) { - $variables[$use->var->name] = true; + $variables[$use->var->name] = \true; if ($use->byRef) { $this->variables->top()->addVar($use->var->name); } @@ -146,7 +141,7 @@ public function push(Node $node): void } elseif ($node instanceof ArrowFunction) { $variables += $this->variables->top()->getVars(); } - $this->variables->push(new VariableContext($variables)); + $this->variables->push(new \Phabel\VariableContext($variables)); } elseif ($node instanceof Assign || $node instanceof AssignOp || $node instanceof AssignRef) { $this->populateVars($node->var); } elseif ($node instanceof MethodCall || $node instanceof StaticCall || $node instanceof FuncCall) { @@ -167,7 +162,7 @@ public function push(Node $node): void * * @return void */ - private function populateVars(Node $node): void + private function populateVars(Node $node) { while ($node instanceof ArrayDimFetch && $node->var instanceof ArrayDimFetch) { $node = $node->var; @@ -187,10 +182,10 @@ private function populateVars(Node $node): void * * @return void */ - public function pop(): void + public function pop() { $popped = $this->parents->pop(); - if ($popped instanceof RootNode || $popped instanceof FunctionLike) { + if ($popped instanceof \Phabel\RootNode || $popped instanceof FunctionLike) { $poppedVars = $this->variables->pop(); if ($popped instanceof ArrowFunction) { $this->variables->top()->addVars($poppedVars->getVars()); @@ -202,9 +197,13 @@ public function pop(): void * * @return Variable */ - public function getVariable(): Variable + public function getVariable() { - return new Variable($this->variables->top()->getVar()); + $phabelReturn = new Variable($this->variables->top()->getVar()); + if (!$phabelReturn instanceof Variable) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Variable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Get child currently being iterated on. @@ -212,9 +211,13 @@ public function getVariable(): Variable * @param Node $node * @return Node */ - public static function getCurrentChild(Node $node): Node + public static function getCurrentChild(Node $node) { - return self::getCurrentChildByRef($node); + $phabelReturn = self::getCurrentChildByRef($node); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Get child currently being iterated on, by reference. @@ -222,16 +225,24 @@ public static function getCurrentChild(Node $node): Node * @param Node $node * @return Node */ - public static function &getCurrentChildByRef(Node $node): Node + public static function &getCurrentChildByRef(Node $node) { - if (!$subNode = $node->getAttribute('currentNode')) { + if (!($subNode = $node->getAttribute('currentNode'))) { throw new \RuntimeException('Node is not a part of the current AST stack!'); } - $child = &$node->{$subNode}; - if (null !== $index = $node->getAttribute('currentNodeIndex')) { - return $child[$index]; + $child =& $node->{$subNode}; + if (null !== ($index = $node->getAttribute('currentNodeIndex'))) { + $phabelReturn =& $child[$index]; + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn =& $child; + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return $child; + return $phabelReturn; } /** * Insert nodes before node. @@ -240,21 +251,21 @@ public static function &getCurrentChildByRef(Node $node): Node * @param Node ...$insert Nodes to insert * @return void */ - public function insertBefore(Node $node, Node ...$insert): void + public function insertBefore(Node $node, Node ...$insert) { if (empty($insert)) { return; } - $found = false; + $found = \false; foreach ($this->parents as $cur) { if ($found) { - $parent = &$this->getCurrentChildByRef($cur); + $parent =& $this->getCurrentChildByRef($cur); break; } if ($this->getCurrentChild($cur) === $node) { - $found = true; - if ($cur instanceof RootNode) { - $parent = &$this->parents[\count($this->parents) - 1]; + $found = \true; + if ($cur instanceof \Phabel\RootNode) { + $parent =& $this->parents[\count($this->parents) - 1]; break; } } @@ -262,7 +273,6 @@ public function insertBefore(Node $node, Node ...$insert): void if (!$found) { throw new \RuntimeException('Node is not a part of the current AST stack!'); } - /** @var string */ $parentKey = $parent->getAttribute('currentNode'); if ($parentKey === 'stmts' && !$parent instanceof ClassLike) { @@ -270,9 +280,9 @@ public function insertBefore(Node $node, Node ...$insert): void $nodeKeyIndex = $parent->getAttribute('currentNodeIndex'); \array_splice($parent->{$parentKey}, $nodeKeyIndex, 0, $insert); $parent->setAttribute('currentNodeIndex', $nodeKeyIndex + \count($insert)); - return; // Done, inserted! + return; + // Done, inserted! } - // Cannot insert, parent is not a statement // // If we insert before a conditional branch of a conditional expression, @@ -281,83 +291,29 @@ public function insertBefore(Node $node, Node ...$insert): void // // Unless we want to go crazy, do not consider side effect evaluation order for stuff like function call arguments, maths and so on. // - if ($parent instanceof BooleanOr && $parentKey === 'right' && Tools::hasSideEffects($parent->right)) { + if ($parent instanceof BooleanOr && $parentKey === 'right' && \Phabel\Tools::hasSideEffects($parent->right)) { $result = $this->getVariable(); - $insert = new If_( - $parent->left, - [ - 'stmts' => [ - new Assign($result, BuilderHelpers::normalizeValue(true)) - ], - 'else' => new Else_([ - ...$insert, - new Assign($result, new Bool_($parent->right)) - ]) - ] - ); + $insert = new If_($parent->left, ['stmts' => [new Assign($result, BuilderHelpers::normalizeValue(\true))], 'else' => new Else_(\array_merge($insert, [new Assign($result, new Bool_($parent->right))]))]); $parent = $result; - } elseif ($parent instanceof BooleanAnd && $parentKey === 'right' && Tools::hasSideEffects($parent->right)) { + } elseif ($parent instanceof BooleanAnd && $parentKey === 'right' && \Phabel\Tools::hasSideEffects($parent->right)) { $result = $this->getVariable(); - $insert = new If_( - $parent->left, - [ - 'stmts' => [ - ...$insert, - new Assign($result, new Bool_($parent->right)) - ], - 'else' => new Else_([ - new Assign($result, BuilderHelpers::normalizeValue(false)) - ]) - ] - ); + $insert = new If_($parent->left, ['stmts' => \array_merge($insert, [new Assign($result, new Bool_($parent->right))]), 'else' => new Else_([new Assign($result, BuilderHelpers::normalizeValue(\false))])]); $parent = $result; - } elseif ($parent instanceof Ternary && $parentKey !== 'cond' && (Tools::hasSideEffects($parent->if) || Tools::hasSideEffects($parent->else))) { + } elseif ($parent instanceof Ternary && $parentKey !== 'cond' && (\Phabel\Tools::hasSideEffects($parent->if) || \Phabel\Tools::hasSideEffects($parent->else))) { $result = $this->getVariable(); - if (!$parent->if) { // ?: - $insert = new If_( - new BooleanNot( - new Assign($result, $parent->cond) - ), - [ - 'stmts' => [ - ...$insert, - new Assign($result, $parent->else) - ] - ] - ); + if (!$parent->if) { + // ?: + $insert = new If_(new BooleanNot(new Assign($result, $parent->cond)), ['stmts' => \array_merge($insert, [new Assign($result, $parent->else)])]); } else { - $insert = new If_( - $parent->cond, - [ - 'stmts' => [ - ...$parentKey === 'left' ? $insert : [], - new Assign($result, $parent->if) - ], - 'else' => new Else_([ - ...$parentKey === 'right' ? $insert : [], - new Assign($result, $parent->else) - ]) - ] - ); + $insert = new If_($parent->cond, ['stmts' => \array_merge($parentKey === 'left' ? $insert : [], [new Assign($result, $parent->if)]), 'else' => new Else_(\array_merge($parentKey === 'right' ? $insert : [], [new Assign($result, $parent->else)]))]); } $parent = $result; - } elseif ($parent instanceof Coalesce && $parentKey === 'right' && Tools::hasSideEffects($parent->right)) { + } elseif ($parent instanceof Coalesce && $parentKey === 'right' && \Phabel\Tools::hasSideEffects($parent->right)) { $result = $this->getVariable(); - $insert = new If_( - Plugin::call( - 'is_null', - new Assign($result, $parent->left) - ), - [ - 'stmts' => [ - ...$insert, - new Assign($result, $parent->right) - ] - ] - ); + $insert = new If_(\Phabel\Plugin::call('is_null', new Assign($result, $parent->left)), ['stmts' => \array_merge($insert, [new Assign($result, $parent->right)])]); $parent = $result; } - $this->insertBefore($parent, ...(\is_array($insert) ? $insert : [$insert])); + $this->insertBefore($parent, ...\is_array($insert) ? $insert : [$insert]); } /** * Insert nodes after node. @@ -366,15 +322,15 @@ public function insertBefore(Node $node, Node ...$insert): void * @param Node ...$nodes Nodes to insert * @return void */ - public function insertAfter(Node $node, Node ...$nodes): void + public function insertAfter(Node $node, Node ...$nodes) { if (empty($nodes)) { return; } - $found = false; + $found = \false; foreach ($this->parents as $parent) { if ($this->getCurrentChild($parent) === $node) { - $found = true; + $found = \true; break; } } @@ -383,56 +339,77 @@ public function insertAfter(Node $node, Node ...$nodes): void } $subNode = $parent->getAttribute('currentNode'); $subNodeIndex = $parent->getAttribute('currentNodeIndex'); - \array_splice($parent->{$subNode}, $subNodeIndex+1, 0, $nodes); + \array_splice($parent->{$subNode}, $subNodeIndex + 1, 0, $nodes); } - /** * Gets name context. * * @return NameContext */ - public function getNameContext(): NameContext + public function getNameContext() { - return $this->nameResolver->getNameContext(); + $phabelReturn = $this->nameResolver->getNameContext(); + if (!$phabelReturn instanceof NameContext) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type NameContext, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Check if the parent node is a statement. * * @return bool */ - public function isParentStmt(): bool + public function isParentStmt() { $parent = $this->parents[0]; - return $parent instanceof Expression || $parent->getAttribute('currentNode') === 'stmts'; + $phabelReturn = $parent instanceof Expression || $parent->getAttribute('currentNode') === 'stmts'; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - /** * Dumps AST. */ - public function dumpAst(Node $stmt): string + public function dumpAst(Node $stmt) { - return $this->prettyPrinter->prettyPrint($stmt instanceof RootNode ? $stmt->stmts : [$stmt]); + $phabelReturn = $this->prettyPrinter->prettyPrint($stmt instanceof \Phabel\RootNode ? $stmt->stmts : [$stmt]); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } /** * Convert a function to a closure. */ - public function toClosure(FunctionLike &$func): void + public function toClosure(FunctionLike &$func) { if ($func instanceof ArrowFunction) { $func = $this->converter->enter($func, $this); } } - /** * Get relative path of current file. * * @return string */ - public function getFile(): string + public function getFile() { - return $this->file; + $phabelReturn = $this->file; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - /** * Set relative path of current file. * @@ -440,23 +417,37 @@ public function getFile(): string * * @return self */ - public function setFile(string $file): self + public function setFile($file) { + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($file) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $file = (string) $file; + } $this->file = $file; - - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Get absolute path of current output file. * * @return string */ - public function getOutputFile(): string + public function getOutputFile() { - return $this->outputFile; + $phabelReturn = $this->outputFile; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - /** * Set absolute path of current input file. * @@ -464,22 +455,37 @@ public function getOutputFile(): string * * @return self */ - public function setInputFile(string $inputFile): self + public function setInputFile($inputFile) { + if (!\is_string($inputFile)) { + if (!(\is_string($inputFile) || \is_object($inputFile) && \method_exists($inputFile, '__toString') || (\is_bool($inputFile) || \is_numeric($inputFile)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($inputFile) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($inputFile) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $inputFile = (string) $inputFile; + } $this->inputFile = $inputFile; - - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Get absolute path of current input file. * * @return string */ - public function getInputFile(): string + public function getInputFile() { - return $this->inputFile; + $phabelReturn = $this->inputFile; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - /** * Set absolute path of current output file. * @@ -487,10 +493,19 @@ public function getInputFile(): string * * @return self */ - public function setOutputFile(string $outputFile): self + public function setOutputFile($outputFile) { + if (!\is_string($outputFile)) { + if (!(\is_string($outputFile) || \is_object($outputFile) && \method_exists($outputFile, '__toString') || (\is_bool($outputFile) || \is_numeric($outputFile)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($outputFile) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($outputFile) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $outputFile = (string) $outputFile; + } $this->outputFile = $outputFile; - - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/EventHandler.php b/src/EventHandler.php index 83af40444..e03349a78 100644 --- a/src/EventHandler.php +++ b/src/EventHandler.php @@ -2,39 +2,77 @@ namespace Phabel; -abstract class EventHandler implements EventHandlerInterface +abstract class EventHandler implements \Phabel\EventHandlerInterface { - public function onStart(): void + public function onStart() { } - public function onBeginPluginGraphResolution(): void + public function onBeginPluginGraphResolution() { } - public function onEndPluginGraphResolution(): void + public function onEndPluginGraphResolution() { } - public function onBeginDirectoryTraversal(int $total, int $workers): void + public function onBeginDirectoryTraversal($total, $workers) { + if (!\is_int($total)) { + if (!(\is_bool($total) || \is_numeric($total))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($total) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($total) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $total = (int) $total; + } + if (!\is_int($workers)) { + if (!(\is_bool($workers) || \is_numeric($workers))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($workers) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($workers) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $workers = (int) $workers; + } } - public function onBeginAstTraversal(string $file): void + public function onBeginAstTraversal($file) { + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($file) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $file = (string) $file; + } } - public function onEndAstTraversal(string $file, int|\Throwable $iterationsOrError): void + public function onEndAstTraversal($file, $iterationsOrError) { + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($file) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $file = (string) $file; + } + if (!($iterationsOrError instanceof \Exception || $iterationsOrError instanceof \Error)) { + if (!\is_int($iterationsOrError)) { + if (!(\is_bool($iterationsOrError) || \is_numeric($iterationsOrError))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($iterationsOrError) must be of type Throwable|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($iterationsOrError) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $iterationsOrError = (int) $iterationsOrError; + } + } } - public function onEndDirectoryTraversal(): void + public function onEndDirectoryTraversal() { } - public function onBeginClassGraphMerge(int $count): void + public function onBeginClassGraphMerge($count) { + if (!\is_int($count)) { + if (!(\is_bool($count) || \is_numeric($count))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($count) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($count) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $count = (int) $count; + } } - public function onClassGraphMerged(): void + public function onClassGraphMerged() { } - public function onEndClassGraphMerge(): void + public function onEndClassGraphMerge() { } - public function onEnd(): void + public function onEnd() { } } diff --git a/src/EventHandlerInterface.php b/src/EventHandlerInterface.php index 7e1624bb0..37cd6e069 100644 --- a/src/EventHandlerInterface.php +++ b/src/EventHandlerInterface.php @@ -4,17 +4,15 @@ interface EventHandlerInterface { - public function onStart(): void; - public function onBeginPluginGraphResolution(): void; - public function onEndPluginGraphResolution(): void; - public function onBeginDirectoryTraversal(int $total, int $workers): void; - public function onBeginAstTraversal(string $file): void; - public function onEndAstTraversal(string $file, int|\Throwable $iterationsOrError): void; - public function onEndDirectoryTraversal(): void; - - public function onBeginClassGraphMerge(int $count): void; - public function onClassGraphMerged(): void; - public function onEndClassGraphMerge(): void; - - public function onEnd(): void; + public function onStart(); + public function onBeginPluginGraphResolution(); + public function onEndPluginGraphResolution(); + public function onBeginDirectoryTraversal($total, $workers); + public function onBeginAstTraversal($file); + public function onEndAstTraversal($file, $iterationsOrError); + public function onEndDirectoryTraversal(); + public function onBeginClassGraphMerge($count); + public function onClassGraphMerged(); + public function onEndClassGraphMerge(); + public function onEnd(); } diff --git a/src/Exception.php b/src/Exception.php index 752ab6d4c..33f8777b6 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -7,15 +7,22 @@ */ class Exception extends \Exception { - private ?string $trace; + private $trace; /** * Get trace. * * @return string */ - public function __toString(): string + public function __toString() { - return $this->trace ?? parent::__toString(); + $phabelReturn = isset($this->trace) ? $this->trace : parent::__toString(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } /** * Constructor. @@ -26,8 +33,32 @@ public function __toString(): string * @param string $file * @param int $line */ - public function __construct(string $message = '', int $code = 0, \Throwable $previous = null, string $file = '', int $line = -1) + public function __construct($message = '', $code = 0, \Throwable $previous = null, $file = '', $line = -1) { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $message = (string) $message; + } + if (!\is_int($code)) { + if (!(\is_bool($code) || \is_numeric($code))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($code) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $code = (int) $code; + } + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($file) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $file = (string) $file; + } + if (!\is_int($line)) { + if (!(\is_bool($line) || \is_numeric($line))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($line) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($line) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $line = (int) $line; + } if ($file !== '') { $this->file = $file; } @@ -36,7 +67,6 @@ public function __construct(string $message = '', int $code = 0, \Throwable $pre } parent::__construct($message, $code, $previous); } - /** * Set the value of trace. * @@ -44,10 +74,21 @@ public function __construct(string $message = '', int $code = 0, \Throwable $pre * * @return self */ - public function setTrace(?string $trace): self + public function setTrace($trace) { + if (!\is_null($trace)) { + if (!\is_string($trace)) { + if (!(\is_string($trace) || \is_object($trace) && \method_exists($trace, '__toString') || (\is_bool($trace) || \is_numeric($trace)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($trace) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($trace) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $trace = (string) $trace; + } + } $this->trace = $trace; - - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/ExceptionWrapper.php b/src/ExceptionWrapper.php index b60fcac2f..ed2b21d0a 100644 --- a/src/ExceptionWrapper.php +++ b/src/ExceptionWrapper.php @@ -3,24 +3,32 @@ namespace Phabel; use SplStack; - final class ExceptionWrapper { - private SplStack $params; + private $params; public function __construct(\Throwable $e) { - $this->params = new SplStack; + $this->params = new SplStack(); do { $this->params->push([$e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine(), $e->__toString()]); } while ($e = $e->getPrevious()); } - public function getException(): Exception + public function getException() { $previous = null; - foreach ($this->params as [$message, $code, $file, $line, $trace]) { - $previous = new Exception($message, $code, $previous, $file, $line); + foreach ($this->params as $phabel_b74d6f1513225dbf) { + $message = $phabel_b74d6f1513225dbf[0]; + $code = $phabel_b74d6f1513225dbf[1]; + $file = $phabel_b74d6f1513225dbf[2]; + $line = $phabel_b74d6f1513225dbf[3]; + $trace = $phabel_b74d6f1513225dbf[4]; + $previous = new \Phabel\Exception($message, $code, $previous, $file, $line); $previous->setTrace($trace); } - return $previous; + $phabelReturn = $previous; + if (!$phabelReturn instanceof \Phabel\Exception) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Exception, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Plugin.php b/src/Plugin.php index 00b678705..3ac9749e7 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -3,34 +3,33 @@ namespace Phabel; use Phabel\PluginGraph\PackageContext; -use PhpParser\Node\Arg; -use PhpParser\Node\Expr; -use PhpParser\Node\Expr\StaticCall; -use PhpParser\Node\Name; - +use Phabel\PhpParser\Node\Arg; +use Phabel\PhpParser\Node\Expr; +use Phabel\PhpParser\Node\Expr\StaticCall; +use Phabel\PhpParser\Node\Name; /** * Plugin. * * @author Daniil Gentili * @license MIT */ -abstract class Plugin extends Tools implements PluginInterface +abstract class Plugin extends \Phabel\Tools implements \Phabel\PluginInterface { /** * Configuration array. */ - private array $config = []; + private $config = []; /** * Package context. */ - private PackageContext $ctx; + private $ctx; /** * Set configuration array. * * @param array $config * @return void */ - public function setConfigArray(array $config): void + public function setConfigArray(array $config) { $this->config = $config; } @@ -39,9 +38,13 @@ public function setConfigArray(array $config): void * * @return array */ - public function getConfigArray(): array + public function getConfigArray() { - return $this->config; + $phabelReturn = $this->config; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Set package context. @@ -50,7 +53,7 @@ public function getConfigArray(): array * * @return void */ - public function setPackageContext(PackageContext $ctx): void + public function setPackageContext(PackageContext $ctx) { $this->ctx = $ctx; } @@ -59,9 +62,13 @@ public function setPackageContext(PackageContext $ctx): void * * @return PackageContext */ - public function getPackageContext(): PackageContext + public function getPackageContext() { - return $this->ctx; + $phabelReturn = $this->ctx; + if (!$phabelReturn instanceof PackageContext) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type PackageContext, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Check if plugin should run. @@ -70,9 +77,22 @@ public function getPackageContext(): PackageContext * * @return boolean */ - public function shouldRun(string $package): bool + public function shouldRun($package) { - return $this->ctx->has($package); + if (!\is_string($package)) { + if (!(\is_string($package) || \is_object($package) && \method_exists($package, '__toString') || (\is_bool($package) || \is_numeric($package)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($package) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($package) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $package = (string) $package; + } + $phabelReturn = $this->ctx->has($package); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * Check if plugin should run. @@ -81,9 +101,22 @@ public function shouldRun(string $package): bool * * @return boolean */ - public function shouldRunFile(string $file): bool + public function shouldRunFile($file) { - return true; + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($file) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $file = (string) $file; + } + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * Call polyfill function from current plugin. @@ -93,89 +126,151 @@ public function shouldRunFile(string $file): bool * * @return StaticCall */ - protected static function callPoly(string $name, ...$parameters): StaticCall + protected static function callPoly($name, ...$parameters) { - return self::call([static::class, $name], ...$parameters); + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $name = (string) $name; + } + $phabelReturn = self::call([static::class, $name], ...$parameters); + if (!$phabelReturn instanceof StaticCall) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type StaticCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * {@inheritDoc} */ - public function getConfig(string $key, $default) + public function getConfig($key, $default) { - return $this->config[$key] ?? $default; + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $key = (string) $key; + } + return isset($this->config[$key]) ? $this->config[$key] : $default; } /** * {@inheritDoc} */ - public function setConfig(string $key, $value): void + public function setConfig($key, $value) { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $key = (string) $key; + } $this->config[$key] = $value; } /** * {@inheritDoc} */ - public function hasConfig(string $key): bool + public function hasConfig($key) { - return isset($this->config[$key]); + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $key = (string) $key; + } + $phabelReturn = isset($this->config[$key]); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * {@inheritDoc} */ - public static function mergeConfigs(array ...$configs): array + public static function mergeConfigs(array ...$configs) { $final = []; - foreach (\array_unique($configs, SORT_REGULAR) as $config) { + foreach (\array_unique($configs, \SORT_REGULAR) as $config) { foreach ($final as $k => $compare) { - if (empty($intersect = \array_intersect_key($config, $compare)) - || $intersect === \array_intersect_key($compare, $config)) { + if (empty($intersect = \array_intersect_key($config, $compare)) || $intersect === \array_intersect_key($compare, $config)) { $final[$k] = $config + $compare; continue 2; } } - $final []= $config; + $final[] = $config; } - return $final; + $phabelReturn = $final; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * {@inheritDoc} */ - public static function splitConfig(array $config): array + public static function splitConfig(array $config) { - return empty($config) ? [[]] : \array_chunk($config, 1, true); + $phabelReturn = empty($config) ? [[]] : \array_chunk($config, 1, \true); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * {@inheritDoc} */ - public static function getComposerRequires(array $config): array + public static function getComposerRequires(array $config) { - return []; + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * {@inheritDoc} */ - public static function next(array $config): array + public static function next(array $config) { - return []; + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * {@inheritDoc} */ - public static function previous(array $config): array + public static function previous(array $config) { - return []; + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * {@inheritDoc} */ - public static function withPrevious(array $config): array + public static function withPrevious(array $config) { - return []; + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * {@inheritDoc} */ - public static function withNext(array $config): array + public static function withNext(array $config) { - return []; + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Plugin/ClassStoragePlugin.php b/src/Plugin/ClassStoragePlugin.php index 965971b72..c927687c4 100644 --- a/src/Plugin/ClassStoragePlugin.php +++ b/src/Plugin/ClassStoragePlugin.php @@ -10,12 +10,11 @@ use Phabel\Context; use Phabel\Plugin; use Phabel\RootNode; -use PhpParser\Builder\Method; -use PhpParser\Builder\Param; -use PhpParser\Node\Stmt\ClassLike; -use PhpParser\Node\Stmt\ClassMethod; -use PhpParser\Node\Stmt\Trait_; - +use Phabel\PhpParser\Builder\Method; +use Phabel\PhpParser\Builder\Param; +use Phabel\PhpParser\Node\Stmt\ClassLike; +use Phabel\PhpParser\Node\Stmt\ClassMethod; +use Phabel\PhpParser\Node\Stmt\Trait_; final class ClassStoragePlugin extends Plugin { /** @@ -23,25 +22,23 @@ final class ClassStoragePlugin extends Plugin * * @var array> */ - public array $classes = []; + public $classes = []; /** * Storage. * * @var array> */ - public array $traits = []; - + public $traits = []; /** * Count. */ - private array $count = []; + private $count = []; /** * Plugins to call during final iteration. * * @var array, true> */ - protected array $finalPlugins = []; - + protected $finalPlugins = []; /** * Check if plugin should run. * @@ -49,9 +46,22 @@ final class ClassStoragePlugin extends Plugin * * @return boolean */ - public function shouldRun(string $package): bool + public function shouldRun($package) { - return true; + if (!\is_string($package)) { + if (!(\is_string($package) || \is_object($package) && \method_exists($package, '__toString') || (\is_bool($package) || \is_numeric($package)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($package) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($package) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $package = (string) $package; + } + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * Check if plugin should run. @@ -60,30 +70,41 @@ public function shouldRun(string $package): bool * * @return boolean */ - public function shouldRunFile(string $file): bool + public function shouldRunFile($file) { - return true; + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($file) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $file = (string) $file; + } + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - /** * Set configuration array. * * @param array $config * @return void */ - public function setConfigArray(array $config): void + public function setConfigArray(array $config) { parent::setConfigArray($config); $this->finalPlugins += $config; } - /** * Enter file. * * @param RootNode $_ * @return void */ - public function enterRoot(RootNode $_, Context $context): void + public function enterRoot(RootNode $_, Context $context) { $file = $context->getFile(); $this->count[$file] = []; @@ -105,42 +126,39 @@ public function enterRoot(RootNode $_, Context $context): void * * @return void */ - public function enter(ClassLike $class, Context $context): void + public function enter(ClassLike $class, Context $context) { $file = $context->getFile(); if ($class->name) { $name = self::getFqdn($class); } else { - $name = "class@anonymous$file"; - $this->count[$file][$name] ??= 0; - $name .= "@".$this->count[$file][$name]++; + $name = "class@anonymous{$file}"; + $this->count[$file][$name] = isset($this->count[$file][$name]) ? $this->count[$file][$name] : 0; + $name .= "@" . $this->count[$file][$name]++; } - $class = clone $class; $stmts = []; foreach ($class->stmts as $stmt) { if (!$stmt instanceof ClassMethod) { continue; } - $stmts []= $stmt; + $stmts[] = $stmt; } $class->stmts = $stmts; $class->setAttribute(ClassStorage::FILE_KEY, $file); - if ($class instanceof Trait_) { $this->traits[$name][$file] = new Builder($class); } else { $this->classes[$name][$file] = new Builder($class, $name); } } - /** * Merge storage with another. * * @param self $other * @return void */ - public function merge($other): void + public function merge($other) { foreach ($other->classes as $class => $classes) { foreach ($classes as $file => $builder) { @@ -160,27 +178,34 @@ public function merge($other): void } $this->finalPlugins += $other->finalPlugins; } - /** * Resolve all classes, optionally fixing up a few methods. * * @return array{0: array, 1: array} Config to pass to new Traverser instance */ - public function finish(): array + public function finish() { $storage = new ClassStorage($this); - $processedAny = false; + $processedAny = \false; do { - $processed = false; + $processed = \false; foreach ($this->finalPlugins as $name => $_) { $processed = $name::processClassGraph($storage) || $processed; } $processedAny = $processed || $processedAny; } while ($processed); if (!$processedAny) { - return [[], []]; + $phabelReturn = [[], []]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } $result = \array_fill_keys(\array_keys($this->finalPlugins), [ClassStorage::class => $storage]); - return [$result, $storage->getFiles()]; + $phabelReturn = [$result, $storage->getFiles()]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Plugin/ComposerSanitizer.php b/src/Plugin/ComposerSanitizer.php index 85f448d44..8576cabb8 100644 --- a/src/Plugin/ComposerSanitizer.php +++ b/src/Plugin/ComposerSanitizer.php @@ -5,7 +5,6 @@ use Phabel\Context; use Phabel\Plugin; use Phabel\RootNode; - /** * Removes the file blocking inclusion of non-transpiled packages. * @@ -13,34 +12,58 @@ */ class ComposerSanitizer extends Plugin { - public const FILE_NAME = '___transpiledWithPhabel.php'; - private const MESSAGE = <<stmts = []; } diff --git a/src/Plugin/GeneratorDetector.php b/src/Plugin/GeneratorDetector.php index cbd7240eb..2a127188b 100644 --- a/src/Plugin/GeneratorDetector.php +++ b/src/Plugin/GeneratorDetector.php @@ -4,10 +4,9 @@ use Phabel\Context; use Phabel\Plugin; -use PhpParser\Node\Expr\Yield_; -use PhpParser\Node\Expr\YieldFrom; -use PhpParser\Node\FunctionLike; - +use Phabel\PhpParser\Node\Expr\Yield_; +use Phabel\PhpParser\Node\Expr\YieldFrom; +use Phabel\PhpParser\Node\FunctionLike; /** * Detect usages of yield and yield from. * @@ -18,31 +17,38 @@ class GeneratorDetector extends Plugin /** * Whether this function is a generator. */ - private const IS_GENERATOR = 'isGenerator'; + const IS_GENERATOR = 'isGenerator'; /** * Return whether this function is a generator. * * @param FunctionLike $node * @return boolean */ - public static function isGenerator(FunctionLike $node): bool + public static function isGenerator(FunctionLike $node) { - return $node->getAttribute(self::IS_GENERATOR, false); + $phabelReturn = $node->getAttribute(self::IS_GENERATOR, \false); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - public function enterYield(Yield_ $node, Context $ctx): void + public function enterYield(Yield_ $node, Context $ctx) { foreach ($ctx->parents as $parent) { if ($parent instanceof FunctionLike) { - $parent->setAttribute(self::IS_GENERATOR, true); + $parent->setAttribute(self::IS_GENERATOR, \true); return; } } } - public function enterYieldFrom(YieldFrom $node, Context $ctx): void + public function enterYieldFrom(YieldFrom $node, Context $ctx) { foreach ($ctx->parents as $parent) { if ($parent instanceof FunctionLike) { - $parent->setAttribute(self::IS_GENERATOR, true); + $parent->setAttribute(self::IS_GENERATOR, \true); return; } } diff --git a/src/Plugin/IssetExpressionFixer.php b/src/Plugin/IssetExpressionFixer.php index 94a6f694c..7640e45a2 100644 --- a/src/Plugin/IssetExpressionFixer.php +++ b/src/Plugin/IssetExpressionFixer.php @@ -3,22 +3,21 @@ namespace Phabel\Plugin; use Phabel\Plugin; -use PhpParser\Node; -use PhpParser\Node\Expr; -use PhpParser\Node\Expr\ArrayDimFetch; -use PhpParser\Node\Expr\ClassConstFetch; -use PhpParser\Node\Expr\Isset_; -use PhpParser\Node\Expr\PropertyFetch; -use PhpParser\Node\Expr\StaticPropertyFetch; -use PhpParser\Node\Expr\Ternary; -use PhpParser\Node\Expr\Variable; -use PhpParser\Node\Scalar\LNumber; -use PhpParser\Node\Scalar\String_; -use PhpParser\Node\VarLikeIdentifier; +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Expr; +use Phabel\PhpParser\Node\Expr\ArrayDimFetch; +use Phabel\PhpParser\Node\Expr\ClassConstFetch; +use Phabel\PhpParser\Node\Expr\Isset_; +use Phabel\PhpParser\Node\Expr\PropertyFetch; +use Phabel\PhpParser\Node\Expr\StaticPropertyFetch; +use Phabel\PhpParser\Node\Expr\Ternary; +use Phabel\PhpParser\Node\Expr\Variable; +use Phabel\PhpParser\Node\Scalar\LNumber; +use Phabel\PhpParser\Node\Scalar\String_; +use Phabel\PhpParser\Node\VarLikeIdentifier; use ReflectionClass; use ReflectionClassConstant; use ReflectionException; - /** * Replace nested expressions in isset. * @@ -33,12 +32,20 @@ class IssetExpressionFixer extends Plugin * @param Node $var * @return Node */ - private static function &extractWorkVar(Node &$var): Node + private static function &extractWorkVar(Node &$var) { if ($var instanceof ArrayDimFetch && $var->var instanceof ArrayDimFetch) { - return self::extractWorkVar($var->var); + $phabelReturn =& self::extractWorkVar($var->var); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - return $var; + $phabelReturn =& $var; + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Wrap boolean isset check. @@ -47,35 +54,27 @@ private static function &extractWorkVar(Node &$var): Node * * @return ArrayDimFetch */ - private static function wrapBoolean(Expr $node): ArrayDimFetch + private static function wrapBoolean(Expr $node) { - return new ArrayDimFetch( - self::callPoly( - 'returnMe', - new Ternary( - $node, - self::fromLiteral([0]), - self::fromLiteral([]), - ) - ), - new LNumber(0) - ); + $phabelReturn = new ArrayDimFetch(self::callPoly('returnMe', new Ternary($node, self::fromLiteral([0]), self::fromLiteral([]))), new LNumber(0)); + if (!$phabelReturn instanceof ArrayDimFetch) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ArrayDimFetch, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public function enter(Isset_ $isset): void + public function enter(Isset_ $isset) { foreach ($isset->vars as $key => &$var) { /** @var array, true>> */ - $subNodes = $this->getConfig(\get_class($var), false); + $subNodes = $this->getConfig(\get_class($var), \false); if (!$subNodes) { continue; } - $workVar = &$this->extractWorkVar($var); - $needsFixing = false; - + $workVar =& $this->extractWorkVar($var); + $needsFixing = \false; foreach ($subNodes as $key => $types) { - if (isset($types[self::getClass($workVar->{$key} ?? '')])) { - $needsFixing = true; + if (isset($types[self::getClass(isset($workVar->{$key}) ? $workVar->{$key} : '')])) { + $needsFixing = \true; break; } } @@ -92,30 +91,19 @@ public function enter(Isset_ $isset): void } break; case StaticPropertyFetch::class: - $workVar = $this->wrapBoolean(self::callPoly( - 'staticExists', - $workVar->class, - $workVar->name instanceof VarLikeIdentifier ? new String_($workVar->name->name) : $workVar->name, - self::fromLiteral(true) - )); + $workVar = $this->wrapBoolean(self::callPoly('staticExists', $workVar->class, $workVar->name instanceof VarLikeIdentifier ? new String_($workVar->name->name) : $workVar->name, self::fromLiteral(\true))); break; case ClassConstFetch::class: - $workVar = $this->wrapBoolean(self::callPoly( - 'staticExists', - $workVar->class, - new String_($workVar->name->name), - self::fromLiteral(false) - )); + $workVar = $this->wrapBoolean(self::callPoly('staticExists', $workVar->class, new String_($workVar->name->name), self::fromLiteral(\false))); break; case Variable::class: $workVar->name = self::callPoly('returnMe', $workVar->name); break; default: - throw new \RuntimeException("Trying to fix unknown isset expression $class"); + throw new \RuntimeException("Trying to fix unknown isset expression {$class}"); } } } - /** * Returns the data provided. * @@ -133,7 +121,6 @@ public static function returnMe($data) { return $data; } - /** * Get name of class. * @@ -141,11 +128,17 @@ public static function returnMe($data) * * @return class-string */ - public static function getClass($class): string + public static function getClass($class) { - return \is_string($class) ? $class : \get_class($class); + $phabelReturn = \is_string($class) ? $class : \get_class($class); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - /** * Check if static property is set. * @@ -155,42 +148,95 @@ public static function getClass($class): string * * @return boolean */ - public static function staticExists($class, string $property, bool $propertyOrConstant): bool + public static function staticExists($class, $property, $propertyOrConstant) { + if (!\is_string($property)) { + if (!(\is_string($property) || \is_object($property) && \method_exists($property, '__toString') || (\is_bool($property) || \is_numeric($property)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($property) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($property) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $property = (string) $property; + } + if (!\is_bool($propertyOrConstant)) { + if (!(\is_bool($propertyOrConstant) || \is_numeric($propertyOrConstant) || \is_string($propertyOrConstant))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($propertyOrConstant) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($propertyOrConstant) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $propertyOrConstant = (bool) $propertyOrConstant; + } $reflectionClass = new ReflectionClass($class); $class = self::getClass($class); if ($propertyOrConstant) { try { $reflection = $reflectionClass->getProperty($property); } catch (ReflectionException $e) { - return false; + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - } elseif (PHP_VERSION_ID >= 70100) { + } elseif (\PHP_VERSION_ID >= 70100) { try { $reflection = new ReflectionClassConstant($class, $property); } catch (ReflectionException $e) { - return false; + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } } else { - return isset($reflectionClass->getConstants()[$property]); + $phabelReturn = isset($reflectionClass->getConstants()[$property]); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - - $classCaller = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['class'] ?? ''; - $allowProtected = false; - $allowPrivate = false; + $classCaller = null !== ($phabel_698a1ed91fd0737e = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 2)) && isset($phabel_698a1ed91fd0737e[1]['class']) ? $phabel_698a1ed91fd0737e[1]['class'] : ''; + $allowProtected = \false; + $allowPrivate = \false; if ($classCaller) { if ($class === $classCaller) { - $allowProtected = $allowPrivate = true; + $allowProtected = $allowPrivate = \true; } elseif ($reflectionClass->isSubclassOf($classCaller) || (new ReflectionClass($classCaller))->isSubclassOf($class)) { - $allowProtected = true; + $allowProtected = \true; } } if ($reflection->isPrivate()) { - return $allowPrivate ? $reflection->getValue() !== null : false; + $phabelReturn = $allowPrivate ? $reflection->getValue() !== null : \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } if ($reflection->isProtected()) { - return $allowProtected ? $reflection->getValue() !== null : false; + $phabelReturn = $allowProtected ? $reflection->getValue() !== null : \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; + } + $phabelReturn = $reflection->getValue() !== null; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; } - return $reflection->getValue() !== null; + return $phabelReturn; } } diff --git a/src/Plugin/ListSplitter.php b/src/Plugin/ListSplitter.php index 3df4fdd05..b048f8426 100644 --- a/src/Plugin/ListSplitter.php +++ b/src/Plugin/ListSplitter.php @@ -4,15 +4,14 @@ use Phabel\Context; use Phabel\Plugin; -use PhpParser\Node\Expr\Array_; -use PhpParser\Node\Expr\ArrayDimFetch; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\AssignRef; -use PhpParser\Node\Expr\List_; -use PhpParser\Node\Expr\Variable; -use PhpParser\Node\Scalar\LNumber; -use PhpParser\Node\Stmt\Foreach_; - +use Phabel\PhpParser\Node\Expr\Array_; +use Phabel\PhpParser\Node\Expr\ArrayDimFetch; +use Phabel\PhpParser\Node\Expr\Assign; +use Phabel\PhpParser\Node\Expr\AssignRef; +use Phabel\PhpParser\Node\Expr\List_; +use Phabel\PhpParser\Node\Expr\Variable; +use Phabel\PhpParser\Node\Scalar\LNumber; +use Phabel\PhpParser\Node\Stmt\Foreach_; /** * Polyfills unsupported list assignments. */ @@ -25,12 +24,12 @@ class ListSplitter extends Plugin * * @return void */ - public function enterForeach(Foreach_ $node, Context $ctx): void + public function enterForeach(Foreach_ $node, Context $ctx) { if (!($node->valueVar instanceof List_ || $node->valueVar instanceof Array_)) { return; } - if (!$this->shouldSplit($node->valueVar) && !($this->getConfig('parentExpr', false) && $ctx->isParentStmt())) { + if (!$this->shouldSplit($node->valueVar) && !($this->getConfig('parentExpr', \false) && $ctx->isParentStmt())) { return; } $list = $node->valueVar; @@ -53,7 +52,6 @@ public function enterAssign(Assign $node, Context $ctx) } $var = $ctx->getVariable(); $assignments = self::splitList($node->var, $var); - $hasReference = $this->hasReference($node->var); if ($ctx->isParentStmt()) { $last = \array_pop($assignments); @@ -73,23 +71,28 @@ public function enterAssign(Assign $node, Context $ctx) * @return (Assign|AssignRef)[] * @psalm-return array */ - public static function splitList($list, Variable $var): array + public static function splitList($list, Variable $var) { $assignments = []; - $key = 0; // Technically a list assignment does not support mixed keys, but we need this for nested assignments + $key = 0; + // Technically a list assignment does not support mixed keys, but we need this for nested assignments foreach ($list->items as $item) { if (!$item) { $key++; continue; } - $curKey = $item->key ?? new LNumber($key++); + $curKey = isset($item->key) ? $item->key : new LNumber($key++); if ($item->byRef) { - $assignments []= new AssignRef($item->value, new ArrayDimFetch($var, $curKey)); + $assignments[] = new AssignRef($item->value, new ArrayDimFetch($var, $curKey)); } else { - $assignments []= new Assign($item->value, new ArrayDimFetch($var, $curKey)); + $assignments[] = new Assign($item->value, new ArrayDimFetch($var, $curKey)); } } - return $assignments; + $phabelReturn = $assignments; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Whether we should act on this list. @@ -98,13 +101,20 @@ public static function splitList($list, Variable $var): array * * @return boolean */ - private function hasReference($list): bool + private function hasReference($list) { $c = $this->getConfigArray(); - $this->setConfigArray(['byRef' => true]); + $this->setConfigArray(['byRef' => \true]); $res = $this->shouldSplit($list); $this->setConfigArray($c); - return $res; + $phabelReturn = $res; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * Whether we should act on this list. @@ -113,22 +123,50 @@ private function hasReference($list): bool * * @return boolean */ - private function shouldSplit($list): bool + private function shouldSplit($list) { foreach ($list->items as $item) { if (!$item) { continue; } - if ($this->getConfig('byRef', false) && $item->byRef) { - return true; - } elseif ($this->getConfig('key', false) && isset($item->key)) { - return true; + if ($this->getConfig('byRef', \false) && $item->byRef) { + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; + } elseif ($this->getConfig('key', \false) && isset($item->key)) { + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } elseif ($item->value instanceof List_ || $item->value instanceof Array_) { if ($this->shouldSplit($item->value)) { - return true; + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } } } - return false; + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } } diff --git a/src/Plugin/Memoization.php b/src/Plugin/Memoization.php index 274d91f4a..fd6b84fe3 100644 --- a/src/Plugin/Memoization.php +++ b/src/Plugin/Memoization.php @@ -4,22 +4,21 @@ use Phabel\Context; use Phabel\Plugin; -use PhpParser\Comment\Doc; -use PhpParser\Node; -use PhpParser\Node\Expr\Array_; -use PhpParser\Node\Expr\ArrayDimFetch; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\Isset_; -use PhpParser\Node\Expr\Variable; -use PhpParser\Node\FunctionLike; -use PhpParser\Node\Identifier; -use PhpParser\Node\Param; -use PhpParser\Node\Stmt\If_; -use PhpParser\Node\Stmt\Return_; -use PhpParser\Node\Stmt\Static_; -use PhpParser\Node\Stmt\StaticVar; +use Phabel\PhpParser\Comment\Doc; +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Expr\Array_; +use Phabel\PhpParser\Node\Expr\ArrayDimFetch; +use Phabel\PhpParser\Node\Expr\Assign; +use Phabel\PhpParser\Node\Expr\Isset_; +use Phabel\PhpParser\Node\Expr\Variable; +use Phabel\PhpParser\Node\FunctionLike; +use Phabel\PhpParser\Node\Identifier; +use Phabel\PhpParser\Node\Param; +use Phabel\PhpParser\Node\Stmt\If_; +use Phabel\PhpParser\Node\Stmt\Return_; +use Phabel\PhpParser\Node\Stmt\Static_; +use Phabel\PhpParser\Node\Stmt\StaticVar; use SplStack; - /** * Enable memoization of results based on a parameter. * @@ -33,13 +32,13 @@ class Memoization extends Plugin * * @var SplStack */ - private SplStack $cache; + private $cache; /** * Constructor function. */ public function __construct() { - $this->cache = new SplStack; + $this->cache = new SplStack(); } /** * Enter functions. @@ -48,23 +47,19 @@ public function __construct() * * @return void */ - public function enterFunctionLike(FunctionLike $node, Context $ctx): void + public function enterFunctionLike(FunctionLike $node, Context $ctx) { - if (!\preg_match_all('/@memoize \$([\w\d_]+)/', (string) ($node->getDocComment() ?? ''), $matches)) { + if (!\preg_match_all('/@memoize \\$([\\w\\d_]+)/', (string) (null !== ($phabel_66a466f6f2606534 = $node->getDocComment()) ? $phabel_66a466f6f2606534 : ''), $matches)) { $this->cache->push(null); return; } - if ($node->getReturnType() instanceof Identifier && $node->getReturnType()->name === 'void') { throw new \RuntimeException('Cannot memoize void function'); } - /** @var Node[] */ $toPrepend = []; - /** @var string[] */ $memoizeParams = $matches[1]; - /** @var array */ $params = []; foreach ($node->getParams() as $param) { @@ -73,39 +68,33 @@ public function enterFunctionLike(FunctionLike $node, Context $ctx): void } $params[$param->var->name] = $param; } - /** @var Variable[] */ $memoizeVars = []; foreach ($memoizeParams as $memoizeVar) { if (!isset($params[$memoizeVar])) { - throw new \RuntimeException('Cannot find memoization parameter $'.$memoizeVar); + throw new \RuntimeException('Cannot find memoization parameter $' . $memoizeVar); } $memoizeParam = $params[$memoizeVar]; if ($memoizeParam->type === null) { - throw new \RuntimeException('Cannot memoize by untyped parameter $'.$memoizeVar); + throw new \RuntimeException('Cannot memoize by untyped parameter $' . $memoizeVar); } if ($memoizeParam->type instanceof Identifier) { if ($memoizeParam->type->name === 'array') { - throw new \RuntimeException('Cannot memoize by array parameter $'.$memoizeVar); + throw new \RuntimeException('Cannot memoize by array parameter $' . $memoizeVar); } if (\in_array($memoizeParam->type->name, ['string', 'int', 'float', 'bool'])) { $memoizeVars[] = $memoizeParam->var; continue; } } - $toPrepend []= Plugin::assign( - $variable = new Variable($memoizeParam->var->name.'___memo'), - Plugin::call('spl_object_hash', $memoizeParam->var) - ); - $memoizeVars []= $variable; + $toPrepend[] = Plugin::assign($variable = new Variable($memoizeParam->var->name . '___memo'), Plugin::call('spl_object_hash', $memoizeParam->var)); + $memoizeVars[] = $variable; } - - $toPrepend []= new Static_([new StaticVar($cache = new Variable('memoizeCache'), new Array_())]); + $toPrepend[] = new Static_([new StaticVar($cache = new Variable('memoizeCache'), new Array_())]); foreach ($memoizeVars as $var) { $cache = new ArrayDimFetch($cache, $var); } - $toPrepend []= new If_(new Isset_([$cache]), [new Return_($cache)]); - + $toPrepend[] = new If_(new Isset_([$cache]), [new Return_($cache)]); $this->cache->push($cache); if (empty($toPrepend)) { return; @@ -121,11 +110,10 @@ public function enterFunctionLike(FunctionLike $node, Context $ctx): void * * @return void */ - public function leaveFunctionLike(FunctionLike $fun, Context $context): void + public function leaveFunctionLike(FunctionLike $fun, Context $context) { $this->cache->pop(); } - /** * Enter return expression. * diff --git a/src/Plugin/NestedExpressionFixer.php b/src/Plugin/NestedExpressionFixer.php index 2e1624ccc..fd1a37043 100644 --- a/src/Plugin/NestedExpressionFixer.php +++ b/src/Plugin/NestedExpressionFixer.php @@ -4,22 +4,21 @@ use Phabel\Context; use Phabel\Plugin; -use PhpParser\Node; -use PhpParser\Node\Expr; -use PhpParser\Node\Expr\ArrayDimFetch; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\BinaryOp\BooleanOr; -use PhpParser\Node\Expr\ClassConstFetch; -use PhpParser\Node\Expr\FuncCall; -use PhpParser\Node\Expr\Instanceof_; -use PhpParser\Node\Expr\MethodCall; -use PhpParser\Node\Expr\New_; -use PhpParser\Node\Expr\PropertyFetch; -use PhpParser\Node\Expr\StaticCall; -use PhpParser\Node\Expr\StaticPropertyFetch; -use PhpParser\Node\Expr\Ternary; -use PhpParser\Node\Expr\Throw_; - +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Expr; +use Phabel\PhpParser\Node\Expr\ArrayDimFetch; +use Phabel\PhpParser\Node\Expr\Assign; +use Phabel\PhpParser\Node\Expr\BinaryOp\BooleanOr; +use Phabel\PhpParser\Node\Expr\ClassConstFetch; +use Phabel\PhpParser\Node\Expr\FuncCall; +use Phabel\PhpParser\Node\Expr\Instanceof_; +use Phabel\PhpParser\Node\Expr\MethodCall; +use Phabel\PhpParser\Node\Expr\New_; +use Phabel\PhpParser\Node\Expr\PropertyFetch; +use Phabel\PhpParser\Node\Expr\StaticCall; +use Phabel\PhpParser\Node\Expr\StaticPropertyFetch; +use Phabel\PhpParser\Node\Expr\Ternary; +use Phabel\PhpParser\Node\Expr\Throw_; /** * Fix nested expressions. * @@ -34,34 +33,45 @@ class NestedExpressionFixer extends Plugin * @param Node $var * @return Node */ - private static function &extractWorkVar(Expr &$var): Expr + private static function &extractWorkVar(Expr &$var) { if ($var instanceof ArrayDimFetch && $var->var instanceof ArrayDimFetch) { - return self::extractWorkVar($var->var); + $phabelReturn =& self::extractWorkVar($var->var); + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - return $var; + $phabelReturn =& $var; + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public function leave(Expr $expr, Context $context): ?Expr + public function leave(Expr $expr, Context $context) { /** @var array, true>> */ - $subNodes = $this->getConfig($class = \get_class($expr), false); + $subNodes = $this->getConfig($class = \get_class($expr), \false); if (!$subNodes) { - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof Expr || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } foreach ($subNodes as $key => $types) { /** @var Expr $value */ - $value = &$expr->{$key}; - if (!isset($types[IssetExpressionFixer::getClass($value ?? '')])) { + $value =& $expr->{$key}; + if (!isset($types[\Phabel\Plugin\IssetExpressionFixer::getClass(isset($value) ? $value : '')])) { if (!$value instanceof Expr) { continue; } - $workVar = &$this->extractWorkVar($value); + $workVar =& $this->extractWorkVar($value); if (!isset($types[\get_class($workVar)])) { continue; } } else { - $workVar = &$value; + $workVar =& $value; } switch (\get_class($workVar)) { case Throw_::class: @@ -74,21 +84,22 @@ public function leave(Expr $expr, Context $context): ?Expr case MethodCall::class: case Instanceof_::class: if ($expr instanceof Instanceof_ && $key === 'class') { - return self::callPoly('instanceOf', $expr->expr, $expr->class); + $phabelReturn = self::callPoly('instanceOf', $expr->expr, $expr->class); + if (!($phabelReturn instanceof Expr || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } $value = self::callPoly('returnMe', $value); break; case New_::class: case ClassConstFetch::class: $valueCopy = $value; - return new Ternary( - new BooleanOr( - new Assign($value = $context->getVariable(), $valueCopy), - self::fromLiteral(true) - ), - $expr, - self::fromLiteral(false) - ); + $phabelReturn = new Ternary(new BooleanOr(new Assign($value = $context->getVariable(), $valueCopy), self::fromLiteral(\true)), $expr, self::fromLiteral(\false)); + if (!($phabelReturn instanceof Expr || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; case StaticCall::class: case StaticPropertyFetch::class: case FuncCall::class: @@ -96,12 +107,15 @@ public function leave(Expr $expr, Context $context): ?Expr $context->insertBefore($expr, new Assign($value = $context->getVariable(), $valueCopy)); break; default: - throw new \RuntimeException("Trying to fix unknown nested expression $class"); + throw new \RuntimeException("Trying to fix unknown nested expression {$class}"); } } - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof Expr || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Returns the data provided. * @@ -119,7 +133,6 @@ public static function returnMe($data) { return $data; } - /** * Throws the exception provided. * @@ -135,7 +148,6 @@ public static function throwMe(\Throwable $throwable) { throw $throwable; } - /** * Check if a is instance of b. * @@ -144,13 +156,23 @@ public static function throwMe(\Throwable $throwable) * * @return boolean */ - public static function instanceOf($a, $b): bool + public static function instanceOf($a, $b) { - return $a instanceof $b; + $phabelReturn = \Phabel\Target\Php70\ThrowableReplacer::isInstanceofThrowable($a, $b); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - - public static function next(array $config): array + public static function next(array $config) { - return [NewFixer::class]; + $phabelReturn = [\Phabel\Plugin\NewFixer::class]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Plugin/NewFixer.php b/src/Plugin/NewFixer.php index 7baedddc9..c8710160f 100644 --- a/src/Plugin/NewFixer.php +++ b/src/Plugin/NewFixer.php @@ -4,16 +4,15 @@ use Phabel\Context; use Phabel\Plugin; -use PhpParser\Node; -use PhpParser\Node\Expr; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\BinaryOp\BooleanOr; -use PhpParser\Node\Expr\Instanceof_; -use PhpParser\Node\Expr\New_; -use PhpParser\Node\Expr\Ternary; -use PhpParser\Node\Scalar; -use PhpParser\NodeFinder; - +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Expr; +use Phabel\PhpParser\Node\Expr\Assign; +use Phabel\PhpParser\Node\Expr\BinaryOp\BooleanOr; +use Phabel\PhpParser\Node\Expr\Instanceof_; +use Phabel\PhpParser\Node\Expr\New_; +use Phabel\PhpParser\Node\Expr\Ternary; +use Phabel\PhpParser\Node\Scalar; +use Phabel\PhpParser\NodeFinder; /** * Fix certain new expressions. * @@ -21,40 +20,47 @@ */ class NewFixer extends Plugin { - private NodeFinder $finder; + private $finder; public function __construct() { - $this->finder = new NodeFinder; + $this->finder = new NodeFinder(); } - private function isParenthesised(Node $node): bool + private function isParenthesised(Node $node) { - return !($node instanceof Expr\Variable - || $node instanceof Node\Name - || $node instanceof Expr\ArrayDimFetch - || $node instanceof Expr\PropertyFetch - || $node instanceof Expr\NullsafePropertyFetch - || $node instanceof Expr\StaticPropertyFetch - || $node instanceof Expr\Array_ - || $node instanceof Scalar\String_ - || $node instanceof Expr\ConstFetch - || $node instanceof Expr\ClassConstFetch); + $phabelReturn = !($node instanceof Expr\Variable || $node instanceof Node\Name || $node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch || $node instanceof Expr\NullsafePropertyFetch || $node instanceof Expr\StaticPropertyFetch || $node instanceof Expr\Array_ || $node instanceof Scalar\String_ || $node instanceof Expr\ConstFetch || $node instanceof Expr\ClassConstFetch); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - private function hasParenthesised(Node $node): bool + private function hasParenthesised(Node $node) { - return $node instanceof Expr && $this->finder->findFirst($node, fn (Node $node): bool => $this->isParenthesised($node)) !== null; + $phabelReturn = $node instanceof Expr && $this->finder->findFirst($node, function (Node $node) { + $phabelReturn = $this->isParenthesised($node); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; + }) !== null; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } public function enterNew(New_ $new, Context $context) { if ($this->hasParenthesised($new->class)) { $valueCopy = $new->class; - return new Ternary( - new BooleanOr( - new Assign($new->class = $context->getVariable(), $valueCopy), - self::fromLiteral(true) - ), - $new, - self::fromLiteral(false) - ); + return new Ternary(new BooleanOr(new Assign($new->class = $context->getVariable(), $valueCopy), self::fromLiteral(\true)), $new, self::fromLiteral(\false)); } } public function enterInstanceof(Instanceof_ $expr) @@ -71,8 +77,15 @@ public function enterInstanceof(Instanceof_ $expr) * * @return boolean */ - public static function instanceOf($a, $b): bool + public static function instanceOf($a, $b) { - return $a instanceof $b; + $phabelReturn = \Phabel\Target\Php70\ThrowableReplacer::isInstanceofThrowable($a, $b); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } } diff --git a/src/Plugin/PhabelTestGenerator.php b/src/Plugin/PhabelTestGenerator.php index e8ee1cf52..4a7492088 100644 --- a/src/Plugin/PhabelTestGenerator.php +++ b/src/Plugin/PhabelTestGenerator.php @@ -4,9 +4,8 @@ use Phabel\Plugin; use Phabel\Target\Php; -use PhpParser\Node\Name; -use PhpParser\Node\Scalar\String_; - +use Phabel\PhpParser\Node\Name; +use Phabel\PhpParser\Node\Scalar\String_; /** * Replace phabel test namespaces with appropriate version. * @@ -14,31 +13,60 @@ */ class PhabelTestGenerator extends Plugin { - private function tryReplace(string $in): string + private function tryReplace($in) { - return \preg_replace("~PhabelTest(\\\\+)Target\d*~", 'PhabelTest$1Target'.$this->getConfig('target', ''), $in); + if (!\is_string($in)) { + if (!(\is_string($in) || \is_object($in) && \method_exists($in, '__toString') || (\is_bool($in) || \is_numeric($in)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($in) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($in) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $in = (string) $in; + } + $phabelReturn = \preg_replace("~PhabelTest(\\\\+)Target\\d*~", 'PhabelTest$1Target' . $this->getConfig('target', ''), $in); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - public function enter(Name $name): ?Name + public function enter(Name $name) { - if (\preg_match("~PhabelTest\\\\+Target\d*~", $name->toString())) { + if (\preg_match("~PhabelTest\\\\+Target\\d*~", $name->toString())) { $class = \get_class($name); - return new $class($this->tryReplace($name->toString())); + $phabelReturn = new $class($this->tryReplace($name->toString())); + if (!($phabelReturn instanceof Name || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Name, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = null; + if (!($phabelReturn instanceof Name || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Name, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return null; + return $phabelReturn; } - public function enterLiteral(String_ $str): ?String_ + public function enterLiteral(String_ $str) { - if (\preg_match("~PhabelTest\\\\+Target\d*~", $str->value)) { - return new String_($this->tryReplace($str->value)); + if (\preg_match("~PhabelTest\\\\+Target\\d*~", $str->value)) { + $phabelReturn = new String_($this->tryReplace($str->value)); + if (!($phabelReturn instanceof String_ || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?String_, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof String_ || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?String_, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public static function previous(array $config): array + public static function previous(array $config) { - return [ - Php::class => ['target' => $config['target'] % 1000], - StringConcatOptimizer::class => [], - ]; + $phabelReturn = [Php::class => ['target' => $config['target'] % 1000], \Phabel\Plugin\StringConcatOptimizer::class => []]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Plugin/ReGenerator.php b/src/Plugin/ReGenerator.php index 61bf0da42..82a1cebb7 100644 --- a/src/Plugin/ReGenerator.php +++ b/src/Plugin/ReGenerator.php @@ -5,8 +5,7 @@ use Phabel\Plugin; use Phabel\Target\Php74\ArrowClosure; use Phabel\Traverser; -use PhpParser\Builder\FunctionLike; - +use Phabel\PhpParser\Builder\FunctionLike; /** * Regenerator transformer. * @@ -16,24 +15,27 @@ class ReGenerator extends Plugin { const SHOULD_ATTRIBUTE = 'shouldRegenerate'; - /** * Custom traverser. */ - private Traverser $traverser; + private $traverser; public function __construct() { - $this->traverser = Traverser::fromPlugin(new ReGeneratorInternal); + $this->traverser = Traverser::fromPlugin(new \Phabel\Plugin\ReGeneratorInternal()); } public function enter(FunctionLike $function) { - if (!$function->getAttribute(self::SHOULD_ATTRIBUTE, false)) { + if (!$function->getAttribute(self::SHOULD_ATTRIBUTE, \false)) { return; } $this->traverser->traverseAst($function); } - public static function previous(array $config): array + public static function previous(array $config) { - return [ArrowClosure::class]; + $phabelReturn = [ArrowClosure::class]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Plugin/ReGenerator/ReGenerator.php b/src/Plugin/ReGenerator/ReGenerator.php index b4998dd74..27fcb474f 100644 --- a/src/Plugin/ReGenerator/ReGenerator.php +++ b/src/Plugin/ReGenerator/ReGenerator.php @@ -34,7 +34,6 @@ class ReGenerator implements \Iterator * @var mixed */ public $yieldValue; - /** * Value sent from the outside. * @@ -44,27 +43,23 @@ class ReGenerator implements \Iterator /** * Exception sent from the outside. */ - public ?\Throwable $sentException = null; - + public $sentException = null; /** * Current state of state machine. */ - public int $state = 0; - + public $state = 0; /** * Whether the generator has returned. */ - public bool $returned = false; + public $returned = \false; /** * Whether the generator was started. */ - public bool $started = false; - + public $started = \false; /** * Actual generator function. */ - public \Closure $generator; - + public $generator; /** * Construct regenerator. * @@ -74,7 +69,6 @@ public function __construct(\Closure $function) { $this->generator = $function; } - /** * Get return value. * @@ -84,20 +78,19 @@ public function getReturn() { return $this->returnValue; } - /** * Start generator. * * @return void */ - private function start(): void + private function start() { if (!$this->started) { - ($this->generator)($this->state, $this->variables, $this->yieldKey, $this->yieldValue, $this->sentValue, $this->sentException, $this->returnValue, $this->returned); - $this->started = true; + $phabel_1679ff392dd5e7d5 = $this->generator; + $phabel_1679ff392dd5e7d5($this->state, $this->variables, $this->yieldKey, $this->yieldValue, $this->sentValue, $this->sentException, $this->returnValue, $this->returned); + $this->started = \true; } } - /** * Send value into generator. * @@ -112,9 +105,13 @@ public function send($value) if (!$this->returned) { $this->sentValue = $value; try { - ($this->generator)($this->state, $this->variables, $this->yieldKey, $this->yieldValue, $this->sentValue, $this->sentException, $this->returnValue, $this->returned); - } catch (\Throwable $e) { - $this->returned = true; + $phabel_9fa9aa2d4dbb1eb4 = $this->generator; + $phabel_9fa9aa2d4dbb1eb4($this->state, $this->variables, $this->yieldKey, $this->yieldValue, $this->sentValue, $this->sentException, $this->returnValue, $this->returned); + } catch (\Exception $e) { + $this->returned = \true; + throw $e; + } catch (\Error $e) { + $this->returned = \true; throw $e; } finally { $this->sentValue = null; @@ -136,9 +133,13 @@ public function throw(\Throwable $throwable) if (!$this->returned) { $this->sentException = $value; try { - ($this->generator)($this->state, $this->variables, $this->yieldKey, $this->yieldValue, $this->sentValue, $this->sentException, $this->returnValue, $this->returned); - } catch (\Throwable $e) { - $this->returned = true; + $phabel_eabcc7a56b2bce11 = $this->generator; + $phabel_eabcc7a56b2bce11($this->state, $this->variables, $this->yieldKey, $this->yieldValue, $this->sentValue, $this->sentException, $this->returnValue, $this->returned); + } catch (\Exception $e) { + $this->returned = \true; + throw $e; + } catch (\Error $e) { + $this->returned = \true; throw $e; } finally { $this->sentException = null; @@ -146,7 +147,6 @@ public function throw(\Throwable $throwable) } return $value; } - /** * Get current value. * @@ -172,7 +172,7 @@ public function key() * * @return void */ - public function next(): void + public function next() { $this->send(null); } @@ -181,14 +181,14 @@ public function next(): void * * @return void */ - public function rewind(): void + public function rewind() { if ($this->started && !$this->returned) { throw new \Exception('Cannot rewind a generator that was already run'); } $this->state = 0; - $this->started = false; - $this->returned = false; + $this->started = \false; + $this->returned = \false; $this->returnValue = null; $this->yieldKey = null; $this->yieldValue = null; @@ -202,8 +202,15 @@ public function rewind(): void * * @return boolean */ - public function valid(): bool + public function valid() { - return !$this->returned; + $phabelReturn = !$this->returned; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } } diff --git a/src/Plugin/ReGeneratorInternal.php b/src/Plugin/ReGeneratorInternal.php index 71bf7208f..32fa00d09 100644 --- a/src/Plugin/ReGeneratorInternal.php +++ b/src/Plugin/ReGeneratorInternal.php @@ -3,10 +3,9 @@ namespace Phabel\Plugin; use Phabel\Plugin; -use PhpParser\Node; -use PhpParser\Node\FunctionLike; +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\FunctionLike; use SplQueue; - /** * Internal regenerator traversor. * @@ -20,11 +19,11 @@ class ReGeneratorInternal extends Plugin * * @var SplQueue> */ - private SplQueue $states; + private $states; public function __construct() { - $this->states = new SplQueue; - $this->states->enqueue(new SplQueue); + $this->states = new SplQueue(); + $this->states->enqueue(new SplQueue()); } /** * Push node to current case. @@ -33,14 +32,21 @@ public function __construct() * * @return void */ - private function pushNode(Node $node): void + private function pushNode(Node $node) { $this->states->top()->enqueue($node); } - private function pushState(): int + private function pushState() { - $this->states->enqueue(new SplQueue); - return $this->states->count()-1; + $this->states->enqueue(new SplQueue()); + $phabelReturn = $this->states->count() - 1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } public function enterRoot(FunctionLike $func) { diff --git a/src/Plugin/StmtExprWrapper.php b/src/Plugin/StmtExprWrapper.php index 780976079..acf972dc0 100644 --- a/src/Plugin/StmtExprWrapper.php +++ b/src/Plugin/StmtExprWrapper.php @@ -4,19 +4,26 @@ use Phabel\Context; use Phabel\Plugin; -use PhpParser\Node\Expr; -use PhpParser\Node\Stmt\Expression; - +use Phabel\PhpParser\Node\Expr; +use Phabel\PhpParser\Node\Stmt\Expression; /** * Wraps standalone expressions in statements into Stmt\Expressions. */ class StmtExprWrapper extends Plugin { - public function enter(Expr $expr, Context $ctx): ?Expression + public function enter(Expr $expr, Context $ctx) { if ($ctx->parents[0]->getAttribute('currentNode') === 'stmts') { - return new Expression($expr); + $phabelReturn = new Expression($expr); + if (!($phabelReturn instanceof Expression || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Expression, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = null; + if (!($phabelReturn instanceof Expression || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Expression, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return null; + return $phabelReturn; } } diff --git a/src/Plugin/StringConcatOptimizer.php b/src/Plugin/StringConcatOptimizer.php index 92cb0945a..6460731a0 100644 --- a/src/Plugin/StringConcatOptimizer.php +++ b/src/Plugin/StringConcatOptimizer.php @@ -4,11 +4,10 @@ use Phabel\Context; use Phabel\Plugin; -use PhpParser\Node; -use PhpParser\Node\Expr\BinaryOp\Concat; -use PhpParser\Node\Scalar\String_; +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Expr\BinaryOp\Concat; +use Phabel\PhpParser\Node\Scalar\String_; use SplQueue; - /** * Optimizes concatenation of multiple strings. * @@ -30,33 +29,44 @@ private function enqueue(Concat $concat, SplQueue $queue) $queue->enqueue($concat->right); } } - public function enter(Concat $concat, Context $ctx): ?Node + public function enter(Concat $concat, Context $ctx) { if ($ctx->parents->top() instanceof Concat) { - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof Node || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - $concatQueue = new SplQueue; + $concatQueue = new SplQueue(); $this->enqueue($concat, $concatQueue); - $newQueue = new SplQueue; + $newQueue = new SplQueue(); $prevNode = $concatQueue->dequeue(); while ($concatQueue->count()) { $node = $concatQueue->dequeue(); if ($node instanceof String_ && $prevNode instanceof String_) { - $prevNode = new String_($prevNode->value.$node->value); + $prevNode = new String_($prevNode->value . $node->value); } else { $newQueue->enqueue($prevNode); $prevNode = $node; } } $newQueue->enqueue($prevNode); - if ($newQueue->count() === 1) { - return $newQueue->dequeue(); + $phabelReturn = $newQueue->dequeue(); + if (!($phabelReturn instanceof Node || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } $concat = new Concat($newQueue->dequeue(), $newQueue->dequeue()); while ($newQueue->count()) { $concat = new Concat($concat, $newQueue->dequeue()); } - return $concat; + $phabelReturn = $concat; + if (!($phabelReturn instanceof Node || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Plugin/TypeHintReplacer.php b/src/Plugin/TypeHintReplacer.php index c9bbc4dd3..62e21eb7c 100644 --- a/src/Plugin/TypeHintReplacer.php +++ b/src/Plugin/TypeHintReplacer.php @@ -5,50 +5,49 @@ use Phabel\Context; use Phabel\Plugin; use Phabel\Target\Php70\AnonymousClass\AnonymousClassInterface; -use PhpParser\BuilderHelpers; -use PhpParser\Node; -use PhpParser\Node\Arg; -use PhpParser\Node\Expr; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\AssignRef; -use PhpParser\Node\Expr\BinaryOp\BooleanAnd; -use PhpParser\Node\Expr\BinaryOp\BooleanOr; -use PhpParser\Node\Expr\BinaryOp\Concat; -use PhpParser\Node\Expr\BinaryOp\Plus; -use PhpParser\Node\Expr\BooleanNot; -use PhpParser\Node\Expr\Cast; -use PhpParser\Node\Expr\Cast\Bool_; -use PhpParser\Node\Expr\Cast\Double; -use PhpParser\Node\Expr\Cast\Int_; -use PhpParser\Node\Expr\Cast\String_ as CastString_; -use PhpParser\Node\Expr\ClassConstFetch; -use PhpParser\Node\Expr\ConstFetch; -use PhpParser\Node\Expr\Instanceof_; -use PhpParser\Node\Expr\New_; -use PhpParser\Node\Expr\Variable; -use PhpParser\Node\FunctionLike; -use PhpParser\Node\Identifier; -use PhpParser\Node\Name; -use PhpParser\Node\Name\FullyQualified; -use PhpParser\Node\NullableType; -use PhpParser\Node\Param; -use PhpParser\Node\Scalar\LNumber; -use PhpParser\Node\Scalar\MagicConst\Function_ as MagicConstFunction_; -use PhpParser\Node\Scalar\MagicConst\Method; -use PhpParser\Node\Scalar\String_; -use PhpParser\Node\Stmt\Class_ as StmtClass_; -use PhpParser\Node\Stmt\ClassLike; -use PhpParser\Node\Stmt\ClassMethod; -use PhpParser\Node\Stmt\Else_; -use PhpParser\Node\Stmt\Expression; -use PhpParser\Node\Stmt\Foreach_; -use PhpParser\Node\Stmt\If_; -use PhpParser\Node\Stmt\Interface_; -use PhpParser\Node\Stmt\Return_; -use PhpParser\Node\Stmt\Throw_; -use PhpParser\Node\UnionType; +use Phabel\PhpParser\BuilderHelpers; +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Arg; +use Phabel\PhpParser\Node\Expr; +use Phabel\PhpParser\Node\Expr\Assign; +use Phabel\PhpParser\Node\Expr\AssignRef; +use Phabel\PhpParser\Node\Expr\BinaryOp\BooleanAnd; +use Phabel\PhpParser\Node\Expr\BinaryOp\BooleanOr; +use Phabel\PhpParser\Node\Expr\BinaryOp\Concat; +use Phabel\PhpParser\Node\Expr\BinaryOp\Plus; +use Phabel\PhpParser\Node\Expr\BooleanNot; +use Phabel\PhpParser\Node\Expr\Cast; +use Phabel\PhpParser\Node\Expr\Cast\Bool_; +use Phabel\PhpParser\Node\Expr\Cast\Double; +use Phabel\PhpParser\Node\Expr\Cast\Int_; +use Phabel\PhpParser\Node\Expr\Cast\String_ as CastString_; +use Phabel\PhpParser\Node\Expr\ClassConstFetch; +use Phabel\PhpParser\Node\Expr\ConstFetch; +use Phabel\PhpParser\Node\Expr\Instanceof_; +use Phabel\PhpParser\Node\Expr\New_; +use Phabel\PhpParser\Node\Expr\Variable; +use Phabel\PhpParser\Node\FunctionLike; +use Phabel\PhpParser\Node\Identifier; +use Phabel\PhpParser\Node\Name; +use Phabel\PhpParser\Node\Name\FullyQualified; +use Phabel\PhpParser\Node\NullableType; +use Phabel\PhpParser\Node\Param; +use Phabel\PhpParser\Node\Scalar\LNumber; +use Phabel\PhpParser\Node\Scalar\MagicConst\Function_ as MagicConstFunction_; +use Phabel\PhpParser\Node\Scalar\MagicConst\Method; +use Phabel\PhpParser\Node\Scalar\String_; +use Phabel\PhpParser\Node\Stmt\Class_ as StmtClass_; +use Phabel\PhpParser\Node\Stmt\ClassLike; +use Phabel\PhpParser\Node\Stmt\ClassMethod; +use Phabel\PhpParser\Node\Stmt\Else_; +use Phabel\PhpParser\Node\Stmt\Expression; +use Phabel\PhpParser\Node\Stmt\Foreach_; +use Phabel\PhpParser\Node\Stmt\If_; +use Phabel\PhpParser\Node\Stmt\Interface_; +use Phabel\PhpParser\Node\Stmt\Return_; +use Phabel\PhpParser\Node\Stmt\Throw_; +use Phabel\PhpParser\Node\UnionType; use SplStack; - /** * Replace all usages of a certain type in typehints. * @@ -60,25 +59,24 @@ class TypeHintReplacer extends Plugin /** * Force removal of specific typehint via node attribute. */ - private const FORCE_ATTRIBUTE = 'TypeHintReplacer:force'; - - private const IGNORE_RETURN = 0; - private const VOID_RETURN = 1; - private const TYPE_RETURN = 2; + const FORCE_ATTRIBUTE = 'TypeHintReplacer:force'; + const IGNORE_RETURN = 0; + const VOID_RETURN = 1; + const TYPE_RETURN = 2; /** * Stack. * * @var SplStack * @psalm-var SplStack */ - private SplStack $stack; + private $stack; /** * Constructor. */ public function __construct() { /** @psalm-var SplStack */ - $this->stack = new SplStack; + $this->stack = new SplStack(); } /** * Replace typehint. @@ -87,16 +85,40 @@ public function __construct() * * @return bool */ - public static function replace(?Node $type): bool + public static function replace($type) { + if (!($type instanceof Node || \is_null($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($type) must be of type ?Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } if ($type) { - if ($type->getAttribute(self::FORCE_ATTRIBUTE, false)) { - return false; + if ($type->getAttribute(self::FORCE_ATTRIBUTE, \false)) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; + } + $type->setAttribute(self::FORCE_ATTRIBUTE, \true); + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; + } + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - $type->setAttribute(self::FORCE_ATTRIBUTE, true); - return true; + $phabelReturn = (bool) $phabelReturn; } - return false; + return $phabelReturn; } /** * Return whether we replaced this typehint. @@ -105,12 +127,29 @@ public static function replace(?Node $type): bool * * @return boolean */ - public static function replaced(?Node $type): bool + public static function replaced($type) { + if (!($type instanceof Node || \is_null($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($type) must be of type ?Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } if ($type) { - return $type->getAttribute(self::FORCE_ATTRIBUTE, false); + $phabelReturn = $type->getAttribute(self::FORCE_ATTRIBUTE, \false); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; + } + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; } - return true; + return $phabelReturn; } /** * Check if we should replace a void return type. @@ -118,9 +157,19 @@ public static function replaced(?Node $type): bool * @param Node|null $returnType * @return bool */ - private function checkVoid(?Node $returnType): bool + private function checkVoid($returnType) { - return $returnType instanceof Identifier && $returnType->toLowerString() === 'void' && $this->getConfig('void', $this->getConfig('return', $returnType->getAttribute(self::FORCE_ATTRIBUTE))); + if (!($returnType instanceof Node || \is_null($returnType))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($returnType) must be of type ?Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($returnType) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = $returnType instanceof Identifier && $returnType->toLowerString() === 'void' && $this->getConfig('void', $this->getConfig('return', $returnType->getAttribute(self::FORCE_ATTRIBUTE))); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * Resolve special class name. @@ -130,15 +179,17 @@ private function checkVoid(?Node $returnType): bool * * @return Expr */ - private function resolveClassName($type, ?Expr $className): Expr + private function resolveClassName($type, $className) { + if (!($className instanceof Expr || \is_null($className))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($className) must be of type ?Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($className) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } $string = $type instanceof Identifier ? $type->toString() : $type->toCodeString(); - return $type->isSpecialClassName() ? - ( - $string === 'self' && $className - ? $className - : new ClassConstFetch(new Name($string), new Identifier('class')) - ) : new String_($type->toString()); + $phabelReturn = $type->isSpecialClassName() ? $string === 'self' && $className ? $className : new ClassConstFetch(new Name($string), new Identifier('class')) : new String_($type->toString()); + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Reduce multiple conditions to a single not. @@ -146,14 +197,20 @@ private function resolveClassName($type, ?Expr $className): Expr * @param non-empty-list $conditions * @return BooleanNot */ - private static function reduceConditions(array $conditions): BooleanNot + private static function reduceConditions(array $conditions) { $initial = \array_shift($conditions); - return new BooleanNot( - empty($conditions) - ? $initial - : \array_reduce($conditions, fn (Expr $a, Expr $b): BooleanOr => new BooleanOr($a, $b), $initial) - ); + $phabelReturn = new BooleanNot(empty($conditions) ? $initial : \array_reduce($conditions, function (Expr $a, Expr $b) { + $phabelReturn = new BooleanOr($a, $b); + if (!$phabelReturn instanceof BooleanOr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type BooleanOr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + }, $initial)); + if (!$phabelReturn instanceof BooleanNot) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type BooleanNot, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Generate. @@ -165,10 +222,19 @@ private static function reduceConditions(array $conditions): BooleanNot * * @return array{0: bool, 1: Node, 2: (callable(Node...): If_)} Whether the polyfilled gettype should be used, the error message, the condition */ - private function generateConditions(Variable $var, array $types, ?Expr $className, bool $fromNullable = false): array + private function generateConditions(Variable $var, array $types, $className, $fromNullable = \false) { + if (!($className instanceof Expr || \is_null($className))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($className) must be of type ?Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($className) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_bool($fromNullable)) { + if (!(\is_bool($fromNullable) || \is_numeric($fromNullable) || \is_string($fromNullable))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($fromNullable) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($fromNullable) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $fromNullable = (bool) $fromNullable; + } /** @var bool Whether no explicit classes were referenced */ - $noOopTypes = true; + $noOopTypes = \true; /** @var Expr[] */ $typeNames = []; /** @var Expr[] */ @@ -192,72 +258,36 @@ private function generateConditions(Variable $var, array $types, ?Expr $classNam case 'null': $stringType = new String_($typeName); if ($typeName === 'int' || $typeName === 'float') { - $conditions []= [ - Plugin::call("is_$typeName", $var), - new BooleanOr( - Plugin::call("is_bool", $var), - Plugin::call("is_numeric", $var), - ), - $typeName === 'int' ? Int_::class : Double::class, - ]; + $conditions[] = [Plugin::call("is_{$typeName}", $var), new BooleanOr(Plugin::call("is_bool", $var), Plugin::call("is_numeric", $var)), $typeName === 'int' ? Int_::class : Double::class]; } elseif ($typeName === 'bool') { - $conditions []= [ - Plugin::call("is_$typeName", $var), - new BooleanOr( - new BooleanOr( - Plugin::call("is_bool", $var), - Plugin::call("is_numeric", $var), - ), - Plugin::call("is_string", $var), - ), - Bool_::class - ]; + $conditions[] = [Plugin::call("is_{$typeName}", $var), new BooleanOr(new BooleanOr(Plugin::call("is_bool", $var), Plugin::call("is_numeric", $var)), Plugin::call("is_string", $var)), Bool_::class]; } elseif ($typeName === 'string') { - $conditions []= [ - Plugin::call("is_$typeName", $var), - new BooleanOr( - new BooleanOr( - Plugin::call("is_string", $var), - new BooleanAnd( - Plugin::call("is_object", $var), - Plugin::call("method_exists", $var, new String_('__toString')), - ), - ), - new BooleanOr( - Plugin::call("is_bool", $var), - Plugin::call("is_numeric", $var), - ), - ), - CastString_::class - ]; + $conditions[] = [Plugin::call("is_{$typeName}", $var), new BooleanOr(new BooleanOr(Plugin::call("is_string", $var), new BooleanAnd(Plugin::call("is_object", $var), Plugin::call("method_exists", $var, new String_('__toString')))), new BooleanOr(Plugin::call("is_bool", $var), Plugin::call("is_numeric", $var))), CastString_::class]; } else { - $conditions []= Plugin::call("is_$typeName", $var); + $conditions[] = Plugin::call("is_{$typeName}", $var); } if (\in_array($typeName, ['object', 'callable'])) { - $oopNames []= $stringType; + $oopNames[] = $stringType; } else { - $typeNames []= $stringType; + $typeNames[] = $stringType; } break; case 'iterable': $stringType = new String_('iterable'); - $conditions []= new BooleanOr( - Plugin::call("is_array", $var), - new Instanceof_($var, new FullyQualified(\Traversable::class)) - ); - $oopNames []= $stringType; + $conditions[] = new BooleanOr(Plugin::call("is_array", $var), new Instanceof_($var, new FullyQualified(\Traversable::class))); + $oopNames[] = $stringType; break; default: - $noOopTypes = false; + $noOopTypes = \false; $stringType = $this->resolveClassName($type, $className); - $conditions []= new Instanceof_($var, new Name($typeName)); - $oopNames []= $stringType; + $conditions[] = new Instanceof_($var, new Name($typeName)); + $oopNames[] = $stringType; } } else { - $noOopTypes = false; + $noOopTypes = \false; $stringType = $this->resolveClassName($type, $className); - $conditions []= new Instanceof_($var, $type); - $oopNames []= $stringType; + $conditions[] = new Instanceof_($var, $type); + $oopNames[] = $stringType; } } if (\count($typeNames) + \count($oopNames) > 1) { @@ -270,7 +300,7 @@ private function generateConditions(Variable $var, array $types, ?Expr $classNam } if ($fromNullable) { $stringType = new Concat(new String_('?'), $stringType); - $conditions []= Plugin::call("is_null", $var); + $conditions[] = Plugin::call("is_null", $var); } $splitConditions = []; $currentConditions = []; @@ -278,52 +308,54 @@ private function generateConditions(Variable $var, array $types, ?Expr $classNam if (\is_array($condition)) { if ($currentConditions) { $currentConditions = $this->reduceConditions($currentConditions); - $splitConditions []= fn (Node ...$stmts): If_ => new If_( - $currentConditions, - ['stmts' => $stmts] - ); + $splitConditions[] = function (Node ...$stmts) use($currentConditions) { + $phabelReturn = new If_($currentConditions, ['stmts' => $stmts]); + if (!$phabelReturn instanceof If_) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type If_, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + }; } $currentConditions = []; - - [$conditionsStrict, $conditionsLoose, $castLoose] = $condition; + list($conditionsStrict, $conditionsLoose, $castLoose) = $condition; $conditionsStrict = new BooleanNot($conditionsStrict); $conditionsLoose = new BooleanNot($conditionsLoose); - $splitConditions []= fn (Node ...$stmts): If_ => new If_( - $conditionsStrict, - ['stmts' => [ - new If_( - $conditionsLoose, - [ - 'stmts' => $stmts, - 'else' => new Else_([ - new Expression(new Assign($var, new $castLoose($var))), - ]), - ] - ) - ]] - ); + $splitConditions[] = function (Node ...$stmts) use($conditionsStrict, $conditionsLoose, $var, $castLoose) { + $phabelReturn = new If_($conditionsStrict, ['stmts' => [new If_($conditionsLoose, ['stmts' => $stmts, 'else' => new Else_([new Expression(new Assign($var, new $castLoose($var)))])])]]); + if (!$phabelReturn instanceof If_) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type If_, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + }; } else { - $currentConditions []= $condition; + $currentConditions[] = $condition; } } if ($currentConditions) { $currentConditions = $this->reduceConditions($currentConditions); - $splitConditions []= fn (Node ...$stmts): If_ => new If_( - $currentConditions, - ['stmts' => $stmts] - ); - } - return [ - $noOopTypes, - $stringType, - function (Node ...$expr) use ($splitConditions): If_ { - $prev = $expr; - foreach ($splitConditions as $func) { - $prev = [$func(...$prev)]; + $splitConditions[] = function (Node ...$stmts) use($currentConditions) { + $phabelReturn = new If_($currentConditions, ['stmts' => $stmts]); + if (!$phabelReturn instanceof If_) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type If_, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return $prev[0]; + return $phabelReturn; + }; + } + $phabelReturn = [$noOopTypes, $stringType, function (Node ...$expr) use($splitConditions) { + $prev = $expr; + foreach ($splitConditions as $func) { + $prev = [$func(...$prev)]; + } + $phabelReturn = $prev[0]; + if (!$phabelReturn instanceof If_) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type If_, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - ]; + return $phabelReturn; + }]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Strip typehint. @@ -335,26 +367,68 @@ function (Node ...$expr) use ($splitConditions): If_ { * * @return null|array{0: bool, 1: Node, 2: (callable(Node...): If_)} Whether the polyfilled gettype should be used, the error message, the condition */ - private function strip(Variable $var, ?Node $type, ?Expr $className, bool $nullish, bool $force = false): ?array + private function strip(Variable $var, $type, $className, $nullish, $force = \false) { + if (!($type instanceof Node || \is_null($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($type) must be of type ?Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!($className instanceof Expr || \is_null($className))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($className) must be of type ?Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($className) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_bool($nullish)) { + if (!(\is_bool($nullish) || \is_numeric($nullish) || \is_string($nullish))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($nullish) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($nullish) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $nullish = (bool) $nullish; + } + if (!\is_bool($force)) { + if (!(\is_bool($force) || \is_numeric($force) || \is_string($force))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($force) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($force) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $force = (bool) $force; + } if (!$type) { - return null; + $phabelReturn = null; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - $force = $force || $type->getAttribute(self::FORCE_ATTRIBUTE, false); + $force = $force || $type->getAttribute(self::FORCE_ATTRIBUTE, \false); if ($type instanceof UnionType) { if (!$this->getConfig('union', $force)) { - return null; + $phabelReturn = null; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - return $this->generateConditions($var, $type->types, $className, $nullish); + $phabelReturn = $this->generateConditions($var, $type->types, $className, $nullish); + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } if ($type instanceof NullableType && $this->getConfig('nullable', $force)) { - return $this->generateConditions($var, [$type->type], $className, true); + $phabelReturn = $this->generateConditions($var, [$type->type], $className, \true); + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } $subType = $type instanceof NullableType ? $type->type : $type; if (\in_array($subType->toString(), $this->getConfig('types', [])) || $force) { - return $this->generateConditions($var, [$subType], $className, $nullish || $type instanceof NullableType); + $phabelReturn = $this->generateConditions($var, [$subType], $className, $nullish || $type instanceof NullableType); + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = null; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return null; + return $phabelReturn; } /** * Strip type hints from function. @@ -363,7 +437,7 @@ private function strip(Variable $var, ?Node $type, ?Expr $className, bool $nulli * * @return ?FunctionLike */ - public function enterFunction(FunctionLike $func, Context $ctx): ?FunctionLike + public function enterFunction(FunctionLike $func, Context $ctx) { $functionName = new Method(); $className = null; @@ -373,18 +447,22 @@ public function enterFunction(FunctionLike $func, Context $ctx): ?FunctionLike $parent = $ctx->parents->top(); if ($parent instanceof Interface_ || $func->getStmts() === null) { foreach ($func->getParams() as $param) { - if ($this->strip(new Variable('phabelVariadic'), $param->type, null, false)) { + if ($this->strip(new Variable('phabelVariadic'), $param->type, null, \false)) { $param->type = null; } } if ($this->checkVoid($returnType)) { $func->returnType = null; } - if ($this->strip(new Variable('phabelReturn'), $returnType, null, false, $this->getConfig('return', false))) { + if ($this->strip(new Variable('phabelReturn'), $returnType, null, \false, $this->getConfig('return', \false))) { $func->returnType = null; } $this->stack->push([self::IGNORE_RETURN]); - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof FunctionLike || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?FunctionLike, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } if (!$parent->name) { /** @var StmtClass_ $parent */ @@ -408,111 +486,129 @@ public function enterFunction(FunctionLike $func, Context $ctx): ?FunctionLike $stmts = []; foreach ($func->getParams() as $index => $param) { $nullish = $param->default instanceof ConstFetch && $param->default->name->toLowerString() === 'null'; - if (!$condition = $this->strip($param->variadic ? new Variable('phabelVariadic') : $param->var, $param->type, $className, $nullish)) { + if (!($condition = $this->strip($param->variadic ? new Variable('phabelVariadic') : $param->var, $param->type, $className, $nullish))) { continue; } $index++; - $param->type = null; - [$noOop, $string, $condition] = $condition; - $start = $param->variadic - ? new Concat(new String_("(): Argument #"), new Plus(new LNumber($index), new Variable('phabelVariadicIndex'))) - : new String_("(): Argument #$index ($".$param->var->name.")"); + list($noOop, $string, $condition) = $condition; + $start = $param->variadic ? new Concat(new String_("(): Argument #"), new Plus(new LNumber($index), new Variable('phabelVariadicIndex'))) : new String_("(): Argument #{$index} (\$" . $param->var->name . ")"); $start = new Concat($start, new String_(" must be of type ")); $start = new Concat($start, $string); $start = new Concat($start, new String_(", ")); $start = new Concat($start, self::callPoly('getDebugType', $param->var)); $start = new Concat($start, new String_(" given, called in ")); $start = new Concat($start, self::callPoly('trace')); - $start = new Concat($functionName, $start); - $if = $condition(new Throw_(new New_(new FullyQualified(\TypeError::class), [new Arg($start)]))); if ($param->variadic) { - $stmts []= new Foreach_($param->var, new Variable('phabelVariadic'), ['keyVar' => new Variable('phabelVariadicIndex'), 'stmts' => [$if]]); + $stmts[] = new Foreach_($param->var, new Variable('phabelVariadic'), ['keyVar' => new Variable('phabelVariadicIndex'), 'stmts' => [$if]]); } else { - $stmts []= $if; + $stmts[] = $if; } } if ($stmts) { $ctx->toClosure($func); - $func->stmts = \array_merge($stmts, $func->getStmts() ?? []); + $func->stmts = \array_merge($stmts, null !== ($phabel_b68a02ad93cf5045 = $func->getStmts()) ? $phabel_b68a02ad93cf5045 : []); } - if ($this->checkVoid($returnType)) { $ctx->toClosure($func); $this->stack->push([self::VOID_RETURN]); $func->returnType = null; - return $func; + $phabelReturn = $func; + if (!($phabelReturn instanceof FunctionLike || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?FunctionLike, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } $var = new Variable('phabelReturn'); - if (!$condition = $this->strip($var, $returnType, $className, false, $this->getConfig('return', false))) { + if (!($condition = $this->strip($var, $returnType, $className, \false, $this->getConfig('return', \false)))) { $this->stack->push([self::IGNORE_RETURN]); - return $func; + $phabelReturn = $func; + if (!($phabelReturn instanceof FunctionLike || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?FunctionLike, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } $func->returnType = null; - if (GeneratorDetector::isGenerator($func)) { + if (\Phabel\Plugin\GeneratorDetector::isGenerator($func)) { $this->stack->push([self::IGNORE_RETURN]); - return $func; + $phabelReturn = $func; + if (!($phabelReturn instanceof FunctionLike || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?FunctionLike, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } $ctx->toClosure($func); - $this->stack->push([self::TYPE_RETURN, $functionName, $func->returnsByRef(), ...$condition]); - + $this->stack->push(\array_merge([self::TYPE_RETURN, $functionName, $func->returnsByRef()], $condition)); $stmts = $func->getStmts(); $final = \end($stmts); if (!$final instanceof Return_) { - [, $string, $condition] = $condition; - + list(, $string, $condition) = $condition; $start = new Concat($functionName, new String_("(): Return value must be of type ")); $start = new Concat($start, $string); $start = new Concat($start, new String_(", none returned in ")); $start = new Concat($start, self::callPoly('trace')); - $throw = new Throw_(new New_(new FullyQualified(\TypeError::class), [new Arg($start)])); - $func->stmts []= $throw; + $func->stmts[] = $throw; } - - return $func; + $phabelReturn = $func; + if (!($phabelReturn instanceof FunctionLike || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?FunctionLike, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - public function enterReturn(Return_ $return, Context $ctx): ?Node + public function enterReturn(Return_ $return, Context $ctx) { if ($this->stack->isEmpty()) { - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof Node || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } $current = $this->stack->top(); if ($current[0] === self::IGNORE_RETURN) { - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof Node || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } if ($current[0] === self::VOID_RETURN) { if ($return->expr !== null) { + $phabelReturn = new Throw_(new New_(new FullyQualified(\ParseError::class), [new String_("A void function must not return a value")])); + if (!($phabelReturn instanceof Node || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } // This should be a transpilation error, wait for better stack traces before throwing here - return new Throw_(new New_(new FullyQualified(\ParseError::class), [new String_("A void function must not return a value")])); + return $phabelReturn; + } + $phabelReturn = null; + if (!($phabelReturn instanceof Node || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return null; + return $phabelReturn; } - [, $functionName, $byRef, $noOop, $string, $condition] = $current; - + list(, $functionName, $byRef, $noOop, $string, $condition) = $current; $var = new Variable('phabelReturn'); - $assign = new Expression($byRef && $return->expr ? new AssignRef($var, $return->expr) : new Assign($var, $return->expr ?? BuilderHelpers::normalizeValue(null))); - + $assign = new Expression($byRef && $return->expr ? new AssignRef($var, $return->expr) : new Assign($var, isset($return->expr) ? $return->expr : BuilderHelpers::normalizeValue(null))); $start = new Concat($functionName, new String_("(): Return value must be of type ")); $start = new Concat($start, $string); $start = new Concat($start, new String_(", ")); $start = new Concat($start, self::callPoly('getDebugType', $var)); $start = new Concat($start, new String_(" returned in ")); $start = new Concat($start, self::callPoly('trace')); - - $if = $condition( - new Throw_(new New_(new FullyQualified(\TypeError::class), [new Arg($start)])) - ); - + $if = $condition(new Throw_(new New_(new FullyQualified(\TypeError::class), [new Arg($start)]))); $return->expr = $var; - $ctx->insertBefore($return, $assign, $if); - - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof Node || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - public function leaveFunc(FunctionLike $func): void + public function leaveFunc(FunctionLike $func) { $this->stack->pop(); } @@ -523,8 +619,8 @@ public function leaveFunc(FunctionLike $func): void */ public static function trace() { - $trace = \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]; - return ($trace['file'] ?? '').' on line '.($trace['line'] ?? ''); + $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]; + return (isset($trace['file']) ? $trace['file'] : '') . ' on line ' . (isset($trace['line']) ? $trace['line'] : ''); } /** * Get debug type. @@ -539,13 +635,20 @@ public static function getDebugType($value) } return \get_debug_type($value); } - - public static function next(array $config): array + public static function next(array $config) { - return [StringConcatOptimizer::class]; + $phabelReturn = [\Phabel\Plugin\StringConcatOptimizer::class]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - public static function previous(array $config): array + public static function previous(array $config) { - return [GeneratorDetector::class]; + $phabelReturn = [\Phabel\Plugin\GeneratorDetector::class]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Plugin/VariableFinder.php b/src/Plugin/VariableFinder.php index a3d8f0c19..10b7c05be 100644 --- a/src/Plugin/VariableFinder.php +++ b/src/Plugin/VariableFinder.php @@ -4,10 +4,9 @@ use Phabel\Plugin; use Phabel\Traverser; -use PhpParser\Node; -use PhpParser\Node\Expr\ClosureUse; -use PhpParser\Node\Expr\Variable; - +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Expr\ClosureUse; +use Phabel\PhpParser\Node\Expr\Variable; /** * @author Daniil Gentili * @license MIT @@ -17,11 +16,11 @@ class VariableFinder extends Plugin /** * Singleton. */ - private static self $singleton; + private static $singleton; /** * Traverser. */ - private static Traverser $singletonTraverser; + private static $singletonTraverser; /** * Get found closure uses. * @@ -30,15 +29,25 @@ class VariableFinder extends Plugin * * @return array */ - public static function find(Node $ast, bool $byRef = false): array + public static function find(Node $ast, $byRef = \false) { + if (!\is_bool($byRef)) { + if (!(\is_bool($byRef) || \is_numeric($byRef) || \is_string($byRef))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($byRef) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($byRef) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $byRef = (bool) $byRef; + } if (!isset(self::$singleton)) { - self::$singleton = new self; + self::$singleton = new self(); self::$singletonTraverser = Traverser::fromPlugin(self::$singleton); } self::$singleton->setConfig('byRef', $byRef); - self::$singletonTraverser->traverseAst($ast, null, false); - return self::$singleton->getFound(); + self::$singletonTraverser->traverseAst($ast, null, \false); + $phabelReturn = self::$singleton->getFound(); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Constructor. @@ -51,7 +60,7 @@ private function __construct() * * @var array */ - private array $found = []; + private $found = []; /** * Enter variable. * @@ -61,7 +70,7 @@ private function __construct() public function enter(Variable $var) { if (\is_string($var->name) && $var->name !== 'this') { - $this->found[$var->name]= new ClosureUse($var, $this->getConfig('byRef', false)); + $this->found[$var->name] = new ClosureUse($var, $this->getConfig('byRef', \false)); } } /** @@ -69,10 +78,14 @@ public function enter(Variable $var) * * @return array */ - private function getFound(): array + private function getFound() { $found = $this->found; $this->found = []; - return $found; + $phabelReturn = $found; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Plugin/YieldDetector.php b/src/Plugin/YieldDetector.php index c7def5a71..2f316c478 100644 --- a/src/Plugin/YieldDetector.php +++ b/src/Plugin/YieldDetector.php @@ -4,9 +4,8 @@ use Phabel\Context; use Phabel\Plugin; -use PhpParser\Node\Expr\Yield_; -use PhpParser\Node\FunctionLike; - +use Phabel\PhpParser\Node\Expr\Yield_; +use Phabel\PhpParser\Node\FunctionLike; /** * Detect usages of yield. * @@ -14,11 +13,11 @@ */ class YieldDetector extends Plugin { - public function enterYield(Yield_ $node, Context $ctx): void + public function enterYield(Yield_ $node, Context $ctx) { foreach ($ctx->parents as $parent) { if ($parent instanceof FunctionLike) { - $parent->setAttribute(ReGenerator::SHOULD_ATTRIBUTE, true); + $parent->setAttribute(\Phabel\Plugin\ReGenerator::SHOULD_ATTRIBUTE, \true); return; } } diff --git a/src/PluginCache.php b/src/PluginCache.php index 49756019f..82b1a9ea5 100644 --- a/src/PluginCache.php +++ b/src/PluginCache.php @@ -3,7 +3,6 @@ namespace Phabel; use ReflectionMethod; - /** * Caches plugin information. * @@ -17,14 +16,13 @@ class PluginCache * * @var array, string[]> */ - private static array $enterMethods = []; + private static $enterMethods = []; /** * Leave method names. * * @var array, string[]> */ - private static array $leaveMethods = []; - + private static $leaveMethods = []; /** * Cache method information. * @@ -32,8 +30,14 @@ class PluginCache * * @return void */ - private static function cacheMethods(string $plugin): void + private static function cacheMethods($plugin) { + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } if (!isset(self::$enterMethods[$plugin])) { self::$enterMethods[$plugin] = []; self::$leaveMethods[$plugin] = []; @@ -41,11 +45,11 @@ private static function cacheMethods(string $plugin): void if (\str_starts_with($method, 'enter')) { $reflection = new ReflectionMethod($plugin, $method); $type = $reflection->getParameters()[0]->getType()->getName(); - self::$enterMethods[$plugin][$type] []= $method; + self::$enterMethods[$plugin][$type][] = $method; } elseif (\str_starts_with($method, 'leave')) { $reflection = new ReflectionMethod($plugin, $method); $type = $reflection->getParameters()[0]->getType()->getName(); - self::$leaveMethods[$plugin][$type] []= $method; + self::$leaveMethods[$plugin][$type][] = $method; } } } @@ -59,10 +63,23 @@ private static function cacheMethods(string $plugin): void * * @return boolean */ - public static function canBeRequired(string $plugin): bool + public static function canBeRequired($plugin) { + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } self::cacheMethods($plugin); - return empty(self::$leaveMethods[$plugin]); + $phabelReturn = empty(self::$leaveMethods[$plugin]); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * Return whether this plugin is empty. @@ -71,10 +88,23 @@ public static function canBeRequired(string $plugin): bool * * @return boolean */ - public static function isEmpty(string $plugin): bool + public static function isEmpty($plugin) { + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } self::cacheMethods($plugin); - return empty(self::$leaveMethods[$plugin]) && empty(self::$enterMethods[$plugin]); + $phabelReturn = empty(self::$leaveMethods[$plugin]) && empty(self::$enterMethods[$plugin]); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * Get enter methods array. @@ -83,10 +113,20 @@ public static function isEmpty(string $plugin): bool * * @return array */ - public static function enterMethods(string $plugin): array + public static function enterMethods($plugin) { + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } self::cacheMethods($plugin); - return self::$enterMethods[$plugin]; + $phabelReturn = self::$enterMethods[$plugin]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Get leave methods array. @@ -95,10 +135,20 @@ public static function enterMethods(string $plugin): array * * @return array */ - public static function leaveMethods(string $plugin): array + public static function leaveMethods($plugin) { + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } self::cacheMethods($plugin); - return self::$leaveMethods[$plugin]; + $phabelReturn = self::$leaveMethods[$plugin]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Get previous requirements. @@ -109,15 +159,29 @@ public static function leaveMethods(string $plugin): array * @return array * @psalm-return array, array> */ - public static function previous(string $plugin, array $config): array + public static function previous($plugin, array $config) { - $pluginConfig = $plugin.\json_encode($config); + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } + $pluginConfig = $plugin . \json_encode($config); /** @var array, array, array>> */ static $cache = []; if (isset($cache[$pluginConfig])) { - return $cache[$pluginConfig]; + $phabelReturn = $cache[$pluginConfig]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - return $cache[$pluginConfig] = self::simplify($plugin::previous($config)); + $phabelReturn = $cache[$pluginConfig] = self::simplify($plugin::previous($config)); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Get next requirements. @@ -128,15 +192,29 @@ public static function previous(string $plugin, array $config): array * @return array * @psalm-return array, array> */ - public static function next(string $plugin, array $config): array + public static function next($plugin, array $config) { - $pluginConfig = $plugin.\json_encode($config); + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } + $pluginConfig = $plugin . \json_encode($config); /** @var array, array, array>> */ static $cache = []; if (isset($cache[$pluginConfig])) { - return $cache[$pluginConfig]; + $phabelReturn = $cache[$pluginConfig]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - return $cache[$pluginConfig] = self::simplify($plugin::next($config)); + $phabelReturn = $cache[$pluginConfig] = self::simplify($plugin::next($config)); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Get withPrevious requirements. @@ -147,15 +225,29 @@ public static function next(string $plugin, array $config): array * @return array * @psalm-return array, array> */ - public static function withPrevious(string $plugin, array $config): array + public static function withPrevious($plugin, array $config) { - $pluginConfig = $plugin.\json_encode($config); + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } + $pluginConfig = $plugin . \json_encode($config); /** @var array, array, array>> */ static $cache = []; if (isset($cache[$pluginConfig])) { - return $cache[$pluginConfig]; + $phabelReturn = $cache[$pluginConfig]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - return $cache[$pluginConfig] = self::simplify($plugin::withPrevious($config)); + $phabelReturn = $cache[$pluginConfig] = self::simplify($plugin::withPrevious($config)); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Get withNext requirements. @@ -166,15 +258,29 @@ public static function withPrevious(string $plugin, array $config): array * @return array * @psalm-return array, array> */ - public static function withNext(string $plugin, array $config): array + public static function withNext($plugin, array $config) { - $pluginConfig = $plugin.\json_encode($config); + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } + $pluginConfig = $plugin . \json_encode($config); /** @var array, array, array>> */ static $cache = []; if (isset($cache[$pluginConfig])) { - return $cache[$pluginConfig]; + $phabelReturn = $cache[$pluginConfig]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - return $cache[$pluginConfig] = self::simplify($plugin::withNext($config)); + $phabelReturn = $cache[$pluginConfig] = self::simplify($plugin::withNext($config)); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Simplify requirements. @@ -184,8 +290,12 @@ public static function withNext(string $plugin, array $config): array * @return array * @psalm-return array, array> */ - private static function simplify(array $requirements): array + private static function simplify(array $requirements) { - return isset($requirements[0]) ? \array_fill_keys($requirements, []) : $requirements; + $phabelReturn = isset($requirements[0]) ? \array_fill_keys($requirements, []) : $requirements; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/PluginGraph/CircularException.php b/src/PluginGraph/CircularException.php index c0c5278e6..ee557c55c 100644 --- a/src/PluginGraph/CircularException.php +++ b/src/PluginGraph/CircularException.php @@ -3,7 +3,6 @@ namespace Phabel\PluginGraph; use Phabel\PluginInterface; - /** * Circular reference in plugin graph. * @@ -17,7 +16,7 @@ class CircularException extends \Exception * * @var class-string[] */ - private array $plugins = []; + private $plugins = []; /** * Constructor. * @@ -27,15 +26,19 @@ class CircularException extends \Exception public function __construct(array $plugins, \Throwable $previous = null) { $this->plugins = $plugins; - parent::__construct("Detected circular reference: ".\implode(" => ", $plugins), 0, $previous); + parent::__construct("Detected circular reference: " . \implode(" => ", $plugins), 0, $previous); } /** * Get plugins. * * @return class-string[] */ - public function getPlugins(): array + public function getPlugins() { - return $this->plugins; + $phabelReturn = $this->plugins; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/PluginGraph/Graph.php b/src/PluginGraph/Graph.php index a5c5f4aa7..a67b19263 100644 --- a/src/PluginGraph/Graph.php +++ b/src/PluginGraph/Graph.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\PluginInterface; - /** * Graph API wrapper. * @@ -16,28 +15,31 @@ class Graph /** * Graph instance. */ - private ?GraphInternal $graph = null; + private $graph = null; /** * Resolved graph instance. */ - private ?ResolvedGraph $resolvedGraph = null; + private $resolvedGraph = null; /** * Constructr. */ public function __construct() { - $this->graph = new GraphInternal; + $this->graph = new \Phabel\PluginGraph\GraphInternal(); } /** * Get new package context. * * @return PackageContext */ - public function getPackageContext(): PackageContext + public function getPackageContext() { - return $this->graph->getPackageContext(); + $phabelReturn = $this->graph->getPackageContext(); + if (!$phabelReturn instanceof \Phabel\PluginGraph\PackageContext) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type PackageContext, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Add plugin. * @@ -49,20 +51,35 @@ public function getPackageContext(): PackageContext * * @return Node[] */ - public function addPlugin(string $plugin, array $config, PackageContext $ctx): array + public function addPlugin($plugin, array $config, \Phabel\PluginGraph\PackageContext $ctx) { - return $this->graph->addPlugin($plugin, $config, $ctx); + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } + $phabelReturn = $this->graph->addPlugin($plugin, $config, $ctx); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Flatten graph. * * @return ResolvedGraph */ - public function flatten(): ResolvedGraph + public function flatten() { - $this->resolvedGraph ??= new ResolvedGraph(...$this->graph->flatten()); + $this->resolvedGraph = isset($this->resolvedGraph) ? $this->resolvedGraph : new \Phabel\PluginGraph\ResolvedGraph(...$this->graph->flatten()); $this->graph = null; - while (\gc_collect_cycles()); - return $this->resolvedGraph; + while (\gc_collect_cycles()) { + } + $phabelReturn = $this->resolvedGraph; + if (!$phabelReturn instanceof \Phabel\PluginGraph\ResolvedGraph) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ResolvedGraph, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/PluginGraph/GraphInternal.php b/src/PluginGraph/GraphInternal.php index 8b4d90558..1b36a8c39 100644 --- a/src/PluginGraph/GraphInternal.php +++ b/src/PluginGraph/GraphInternal.php @@ -7,7 +7,6 @@ use Phabel\PluginInterface; use SplObjectStorage; use SplQueue; - /** * Internal graph class. * @@ -21,29 +20,25 @@ class GraphInternal * * @var array, array> */ - private array $plugins = []; - + private $plugins = []; /** * Package contexts. * * @var PackageContext[] */ - private array $packageContexts = []; - + private $packageContexts = []; /** * Stores list of Nodes that are not required by any other node. * * @var SplObjectStorage */ - private SplObjectStorage $unlinkedNodes; - + private $unlinkedNodes; /** * Stores list of Nodes that weren't yet processed. * * @var SplObjectStorage */ - public SplObjectStorage $unprocessedNode; - + public $unprocessedNode; /** * Constructor. */ @@ -52,18 +47,19 @@ public function __construct() $this->unlinkedNodes = new SplObjectStorage(); $this->unprocessedNode = new SplObjectStorage(); } - /** * Get new package context. */ - public function getPackageContext(): PackageContext + public function getPackageContext() { - $packageContext = new PackageContext(); + $packageContext = new \Phabel\PluginGraph\PackageContext(); $this->packageContexts[] = $packageContext; - - return $packageContext; + $phabelReturn = $packageContext; + if (!$phabelReturn instanceof \Phabel\PluginGraph\PackageContext) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type PackageContext, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Add plugin. * @@ -75,11 +71,26 @@ public function getPackageContext(): PackageContext * * @return Node[] */ - public function addPlugin(string $plugin, array $config, PackageContext $ctx): array + public function addPlugin($plugin, array $config, \Phabel\PluginGraph\PackageContext $ctx) { - return \array_map(fn (array $config): Node => $this->addPluginInternal($plugin, $config, $ctx), $plugin::splitConfig($config)); + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } + $phabelReturn = \array_map(function (array $config) use($plugin, $ctx) { + $phabelReturn = $this->addPluginInternal($plugin, $config, $ctx); + if (!$phabelReturn instanceof \Phabel\PluginGraph\Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + }, $plugin::splitConfig($config)); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Add plugin. * @@ -89,39 +100,54 @@ public function addPlugin(string $plugin, array $config, PackageContext $ctx): a * * @psalm-param class-string $plugin Plugin name */ - private function addPluginInternal(string $plugin, array $config, PackageContext $ctx): Node + private function addPluginInternal($plugin, array $config, \Phabel\PluginGraph\PackageContext $ctx) { + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } $configStr = \json_encode($config); if (isset($this->plugins[$plugin][$configStr])) { - return $this->plugins[$plugin][$configStr]->addPackages($ctx); + $phabelReturn = $this->plugins[$plugin][$configStr]->addPackages($ctx); + if (!$phabelReturn instanceof \Phabel\PluginGraph\Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - $this->plugins[$plugin][$configStr] = $node = new Node($this, $ctx); + $this->plugins[$plugin][$configStr] = $node = new \Phabel\PluginGraph\Node($this, $ctx); $this->unlinkedNodes->attach($node); $this->unprocessedNode->attach($node); - - return $node->init($plugin, $config); + $phabelReturn = $node->init($plugin, $config); + if (!$phabelReturn instanceof \Phabel\PluginGraph\Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Set unlinked node as linked. */ - public function linkNode(Node $node): void + public function linkNode(\Phabel\PluginGraph\Node $node) { if ($this->unlinkedNodes->contains($node)) { $this->unlinkedNodes->detach($node); } } - /** * Flatten graph. * * @return array{0: SplQueue>, 1: array>} */ - public function flatten(): array + public function flatten() { if (!$this->plugins) { + $phabelReturn = [new SplQueue(), []]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } /** @psalm-var SplQueue> */ - return [new SplQueue(), []]; + return $phabelReturn; } if ($this->unlinkedNodes->count()) { /** @var Node|null $initNode */ @@ -133,7 +159,7 @@ public function flatten(): array /** @var Node */ $initNode = $node; } - $this->unlinkedNodes = new SplObjectStorage; + $this->unlinkedNodes = new SplObjectStorage(); $this->unlinkedNodes->attach($initNode); $this->unprocessedNode->attach($initNode); $result = $initNode->circular()->flatten(); @@ -143,6 +169,10 @@ public function flatten(): array if ($this->unprocessedNode->count()) { throw new Exception('Did not process entire graph!'); } - return $result; + $phabelReturn = $result; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/PluginGraph/Node.php b/src/PluginGraph/Node.php index ddf6aa492..93d43c821 100644 --- a/src/PluginGraph/Node.php +++ b/src/PluginGraph/Node.php @@ -7,7 +7,6 @@ use Phabel\PluginInterface; use SplObjectStorage; use SplQueue; - /** * Represents a plugin with a certain configuration. * @@ -21,83 +20,74 @@ class Node * * @var Plugins */ - public Plugins $plugin; - + public $plugin; /** * Original plugin name. * * @var class-string */ - private string $name; + private $name; /** * Original plugin name. * * @var class-string */ - private string $nameConcat; - + private $nameConcat; /** * Associated package context. * * @var PackageContext */ - private PackageContext $packageContext; + private $packageContext; /** * Nodes that this node requires. * * @var SplObjectStorage */ - private SplObjectStorage $requires; - + private $requires; /** * Nodes that this node extends. * * @var SplObjectStorage */ - private SplObjectStorage $extends; - + private $extends; /** * Nodes that require this node. * * @var SplObjectStorage */ - private SplObjectStorage $requiredBy; - + private $requiredBy; /** * Nodes that extend this node. * * @var SplObjectStorage */ - private SplObjectStorage $extendedBy; - + private $extendedBy; /** * Graph instance. */ - private GraphInternal $graph; - + private $graph; /** * Whether this node was visited when looking for circular requirements. */ - private bool $visitedCircular = false; - + private $visitedCircular = \false; /** * Whether this node can be required, or only extended. */ - private bool $canBeRequired = true; - + private $canBeRequired = \true; /** * Constructor. * * @param GraphInternal $graph Graph instance */ - public function __construct(GraphInternal $graph, PackageContext $ctx) + public function __construct(\Phabel\PluginGraph\GraphInternal $graph, \Phabel\PluginGraph\PackageContext $ctx) { $this->packageContext = $ctx; $this->graph = $graph; - $this->requiredBy = new SplObjectStorage; - $this->extendedBy = new SplObjectStorage; - $this->requires = new SplObjectStorage; - $this->extends = new SplObjectStorage; + $this->requiredBy = new SplObjectStorage(); + $this->extendedBy = new SplObjectStorage(); + $this->requires = new SplObjectStorage(); + $this->extends = new SplObjectStorage(); } /** * Initialization function. @@ -110,11 +100,16 @@ public function __construct(GraphInternal $graph, PackageContext $ctx) * * @return self */ - public function init(string $plugin, array $pluginConfig): self + public function init($plugin, array $pluginConfig) { + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } $this->name = $plugin; - $this->plugin = new Plugins($plugin, $pluginConfig); - + $this->plugin = new \Phabel\PluginGraph\Plugins($plugin, $pluginConfig); $this->canBeRequired = PluginCache::canBeRequired($plugin); foreach (PluginCache::next($plugin, $pluginConfig) as $class => $config) { foreach ($this->graph->addPlugin($class, $config, $this->packageContext) as $node) { @@ -136,10 +131,12 @@ public function init(string $plugin, array $pluginConfig): self $this->extend($node); } } - - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Make node require another node. * @@ -147,7 +144,7 @@ public function init(string $plugin, array $pluginConfig): self * * @return void */ - private function require(self $node): void + private function require(self $node) { if (!$node->canBeRequired) { $this->extend($node); @@ -159,7 +156,6 @@ private function require(self $node): void } $this->requires->attach($node); $node->requiredBy->attach($this); - $this->graph->linkNode($this); } /** @@ -169,17 +165,15 @@ private function require(self $node): void * * @return void */ - private function extend(self $node): void + private function extend(self $node) { if ($this->requires->contains($node) || $node->requiredBy->contains($this)) { return; } $this->extends->attach($node); $node->extendedBy->attach($this); - $this->graph->linkNode($this); } - /** * Merge node with another node. * @@ -187,7 +181,7 @@ private function extend(self $node): void * * @return Node */ - public function merge(self $other): Node + public function merge(self $other) { if ($other->requires->count() || $other->extends->count()) { throw new Exception('Cannot merge a node that requires other nodes!'); @@ -202,63 +196,68 @@ public function merge(self $other): Node $that->extend($this); $that->extends->detach($other); } - $other->requiredBy = new SplObjectStorage; - $other->extendedBy = new SplObjectStorage; + $other->requiredBy = new SplObjectStorage(); + $other->extendedBy = new SplObjectStorage(); $this->graph->unprocessedNode->detach($other); - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof \Phabel\PluginGraph\Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Look for circular references, while merging package contexts. * * @return self */ - public function circular(): self + public function circular() { if ($this->visitedCircular) { $plugins = [$this->name]; - foreach (\debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, DEBUG_BACKTRACE_PROVIDE_OBJECT) as $frame) { - $plugins []= $frame['object']->name; + foreach (\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, \DEBUG_BACKTRACE_PROVIDE_OBJECT) as $frame) { + $plugins[] = $frame['object']->name; if ($frame['object'] === $this) { break; } } - throw new CircularException($plugins); + throw new \Phabel\PluginGraph\CircularException($plugins); } - $this->visitedCircular = true; - + $this->visitedCircular = \true; foreach ($this->requiredBy as $that) { $this->packageContext->merge($that->circular()->packageContext); } foreach ($this->extendedBy as $that) { $this->packageContext->merge($that->circular()->packageContext); } - - $this->visitedCircular = false; - - return $this; + $this->visitedCircular = \false; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Flatten tree. * * @return array{0: SplQueue>, array>} */ - public function flatten(): array + public function flatten() { /** @var SplQueue */ - $initQueue = new SplQueue; - + $initQueue = new SplQueue(); /** @var SplQueue> */ - $queue = new SplQueue; + $queue = new SplQueue(); $queue->enqueue($initQueue); - $packages = []; $this->flattenInternal($queue, $packages); if ($this->extendedBy->count() || $this->requiredBy->count()) { throw new Exception('Graph resolution has stalled'); } - - return [$queue, $packages]; + $phabelReturn = [$queue, $packages]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Internal flattening. @@ -267,15 +266,15 @@ public function flatten(): array * * @return void */ - private function flattenInternal(SplQueue $queueOfQueues, array &$packages): void + private function flattenInternal(SplQueue $queueOfQueues, array &$packages) { $queue = $queueOfQueues->top(); $this->plugin->enqueue($queue, $this->packageContext, $packages); $this->graph->unprocessedNode->detach($this); do { - $processedAny = false; + $processedAny = \false; $prevNode = null; - $toDetach = new SplQueue; + $toDetach = new SplQueue(); foreach ($this->extendedBy as $node) { $node->extends->detach($this); if (\count($node->requires) + \count($node->extends) === 0) { @@ -291,9 +290,8 @@ private function flattenInternal(SplQueue $queueOfQueues, array &$packages): voi $this->extendedBy->detach($node); $this->graph->unprocessedNode->detach($node); } - $prevNode = null; - $toDetach = new SplQueue; + $toDetach = new SplQueue(); foreach ($this->requiredBy as $node) { $node->requires->detach($this); if (\count($node->requires) + \count($node->extends) === 0) { @@ -309,28 +307,26 @@ private function flattenInternal(SplQueue $queueOfQueues, array &$packages): voi $this->requiredBy->detach($node); $this->graph->unprocessedNode->detach($node); } - - $toDetach = new SplQueue; + $toDetach = new SplQueue(); foreach ($this->extendedBy as $node) { if (\count($node->extends) + \count($node->requires) === 0) { $toDetach->enqueue($node); $node->flattenInternal($queueOfQueues, $packages); - $processedAny = true; + $processedAny = \true; } } foreach ($toDetach as $node) { $this->extendedBy->detach($node); } - - $toDetach = new SplQueue; + $toDetach = new SplQueue(); foreach ($this->requiredBy as $node) { if (\count($node->extends) + \count($node->requires) === 0) { $toDetach->enqueue($node); if (!$queue->isEmpty()) { - $queueOfQueues->enqueue(new SplQueue); + $queueOfQueues->enqueue(new SplQueue()); } $node->flattenInternal($queueOfQueues, $packages); - $processedAny = true; + $processedAny = \true; } } foreach ($toDetach as $node) { @@ -338,7 +334,6 @@ private function flattenInternal(SplQueue $queueOfQueues, array &$packages): voi } } while ($processedAny); } - /** * Add packages from package context. * @@ -346,9 +341,13 @@ private function flattenInternal(SplQueue $queueOfQueues, array &$packages): voi * * @return self */ - public function addPackages(PackageContext $ctx): self + public function addPackages(\Phabel\PluginGraph\PackageContext $ctx) { $this->packageContext->merge($ctx); - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/PluginGraph/PackageContext.php b/src/PluginGraph/PackageContext.php index e2de1e25c..08625efaf 100644 --- a/src/PluginGraph/PackageContext.php +++ b/src/PluginGraph/PackageContext.php @@ -15,7 +15,7 @@ class PackageContext * * @var array */ - private array $packages = []; + private $packages = []; /** * Add package. * @@ -23,9 +23,15 @@ class PackageContext * * @return void */ - public function addPackage(string $package): void + public function addPackage($package) { - $this->packages[$package] = true; + if (!\is_string($package)) { + if (!(\is_string($package) || \is_object($package) && \method_exists($package, '__toString') || (\is_bool($package) || \is_numeric($package)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($package) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($package) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $package = (string) $package; + } + $this->packages[$package] = \true; } /** * Merge two contexts. @@ -34,12 +40,15 @@ public function addPackage(string $package): void * * @return self New context */ - public function merge(self $other): self + public function merge(self $other) { $this->packages += $other->packages; - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Check if a package is present in the package context. * @@ -47,18 +56,34 @@ public function merge(self $other): self * * @return boolean */ - public function has(string $package): bool + public function has($package) { - return isset($this->packages[$package]); + if (!\is_string($package)) { + if (!(\is_string($package) || \is_object($package) && \method_exists($package, '__toString') || (\is_bool($package) || \is_numeric($package)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($package) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($package) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $package = (string) $package; + } + $phabelReturn = isset($this->packages[$package]); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - /** * Get package list. * * @return array */ - public function getPackages(): array + public function getPackages() { - return \array_values($this->packages); + $phabelReturn = \array_values($this->packages); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/PluginGraph/Plugins.php b/src/PluginGraph/Plugins.php index d0e66a9de..d32f2cb7e 100644 --- a/src/PluginGraph/Plugins.php +++ b/src/PluginGraph/Plugins.php @@ -5,7 +5,6 @@ use Phabel\PluginCache; use Phabel\PluginInterface; use SplQueue; - /** * Representation of multiple plugins+configs. * @@ -19,19 +18,23 @@ class Plugins * * @var array, array[]> */ - public array $plugins = []; - + public $plugins = []; /** * Constructor. * * @param class-string $plugin Plugin * @param array $config Config */ - public function __construct(string $plugin, array $config) + public function __construct($plugin, array $config) { + if (!\is_string($plugin)) { + if (!(\is_string($plugin) || \is_object($plugin) && \method_exists($plugin, '__toString') || (\is_bool($plugin) || \is_numeric($plugin)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plugin) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plugin) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $plugin = (string) $plugin; + } $this->plugins[$plugin] = [$config]; } - /** * Merge with other plugins. * @@ -39,7 +42,7 @@ public function __construct(string $plugin, array $config) * * @return void */ - public function merge(self $other): void + public function merge(self $other) { foreach ($other->plugins as $plugin => $configs) { if (isset($this->plugins[$plugin])) { @@ -49,7 +52,6 @@ public function merge(self $other): void } } } - /** * Enqueue plugins. * @@ -57,18 +59,18 @@ public function merge(self $other): void * * @return void */ - public function enqueue(SplQueue $queue, PackageContext $ctx, array &$packages): void + public function enqueue(SplQueue $queue, \Phabel\PluginGraph\PackageContext $ctx, array &$packages) { foreach ($this->plugins as $plugin => $configs) { foreach ($plugin::mergeConfigs(...$configs) as $config) { foreach ($plugin::getComposerRequires($config) as $package => $constraint) { - $packages[$package] ??= []; - $packages[$package][]= $constraint; + $packages[$package] = isset($packages[$package]) ? $packages[$package] : []; + $packages[$package][] = $constraint; } if (PluginCache::isEmpty($plugin)) { continue; } - $pluginObj = new $plugin; + $pluginObj = new $plugin(); $pluginObj->setConfigArray($config); $pluginObj->setPackageContext($ctx); $queue->enqueue($pluginObj); diff --git a/src/PluginGraph/ResolvedGraph.php b/src/PluginGraph/ResolvedGraph.php index fbd4f250a..2e0b72d7f 100644 --- a/src/PluginGraph/ResolvedGraph.php +++ b/src/PluginGraph/ResolvedGraph.php @@ -6,7 +6,6 @@ use Phabel\Plugin\ClassStoragePlugin; use Phabel\PluginInterface; use SplQueue; - /** * Resolved graph. * @@ -20,18 +19,17 @@ final class ResolvedGraph * * @psalm-var SplQueue> */ - private SplQueue $plugins; + private $plugins; /** * Packages. * * @var array */ - private array $packages = []; + private $packages = []; /** * Class storage. */ - private ?ClassStoragePlugin $classStorage = null; - + private $classStorage = null; /** * Constructor. * @@ -40,20 +38,23 @@ final class ResolvedGraph */ public function __construct(SplQueue $plugins, array $packages = []) { - $this->packages = \array_map( - fn (array $constraints): string => \implode(':', \array_unique($constraints)), - $packages - ); - $this->plugins = new SplQueue; + $this->packages = \array_map(function (array $constraints) { + $phabelReturn = \implode(':', \array_unique($constraints)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; + }, $packages); + $this->plugins = new SplQueue(); foreach ($plugins as $queue) { - $newQueue = new SplQueue; + $newQueue = new SplQueue(); foreach ($queue as $plugin) { if ($plugin instanceof ClassStoragePlugin) { if ($this->classStorage) { - $config = $this->classStorage->mergeConfigs( - $this->classStorage->getConfigArray(), - $plugin->getConfigArray() - ); + $config = $this->classStorage->mergeConfigs($this->classStorage->getConfigArray(), $plugin->getConfigArray()); if (\count($config) !== 1) { throw new Exception('Could not merge class storage config!'); } @@ -75,47 +76,61 @@ public function __construct(SplQueue $plugins, array $packages = []) * @return SplQueue * @psalm-return SplQueue> */ - public function getPlugins(): SplQueue + public function getPlugins() { - return $this->plugins; + $phabelReturn = $this->plugins; + if (!$phabelReturn instanceof SplQueue) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type SplQueue, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Get packages. * * @return array * @psalm-return array */ - public function getPackages(): array + public function getPackages() { - return $this->packages; + $phabelReturn = $this->packages; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Get class storage. * * @return ?ClassStoragePlugin */ - public function getClassStorage(): ?ClassStoragePlugin + public function getClassStorage() { - return $this->classStorage; + $phabelReturn = $this->classStorage; + if (!($phabelReturn instanceof ClassStoragePlugin || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?ClassStoragePlugin, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Returns graph debug information. * * @return array */ - public function __debugInfo(): array + public function __debugInfo() { $res = []; foreach ($this->plugins as $queue) { $cur = []; foreach ($queue as $plugin) { - $cur[] = \basename(\str_replace('\\', '/', \get_class($plugin))); //[\get_class($plugin), $plugin->getConfigArray()]; + $cur[] = \basename(\str_replace('\\', '/', \get_class($plugin))); + //[\get_class($plugin), $plugin->getConfigArray()]; } - $res []= $cur; + $res[] = $cur; + } + $phabelReturn = $res; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return $res; + return $phabelReturn; } } diff --git a/src/PluginInterface.php b/src/PluginInterface.php index 10cc0bf64..1d020407b 100644 --- a/src/PluginInterface.php +++ b/src/PluginInterface.php @@ -3,7 +3,6 @@ namespace Phabel; use Phabel\PluginGraph\PackageContext; - /** * Plugin interface. * @@ -19,7 +18,7 @@ interface PluginInterface * * @psalm-return class-string[]|array, array> */ - public static function previous(array $config): array; + public static function previous(array $config); /** * Specify which plugins should run after this plugin. * @@ -32,7 +31,7 @@ public static function previous(array $config): array; * * @psalm-return class-string[]|array, array> */ - public static function next(array $config): array; + public static function next(array $config); /** * Specify which plugins should run before, possibly with this plugin. * @@ -44,7 +43,7 @@ public static function next(array $config): array; * * @psalm-return class-string[]|array, array> */ - public static function withPrevious(array $config): array; + public static function withPrevious(array $config); /** * Specify which plugins should run after, possibly with this plugin. * @@ -52,14 +51,13 @@ public static function withPrevious(array $config): array; * * @psalm-return class-string[]|array, array> */ - public static function withNext(array $config): array; - + public static function withNext(array $config); /** * Specify a list of composer dependencies. * * @return array */ - public static function getComposerRequires(array $config): array; + public static function getComposerRequires(array $config); /** * Set configuration array. * @@ -67,7 +65,7 @@ public static function getComposerRequires(array $config): array; * * @return void */ - public function setConfigArray(array $config): void; + public function setConfigArray(array $config); /** * Set package context. * @@ -75,13 +73,13 @@ public function setConfigArray(array $config): void; * * @return void */ - public function setPackageContext(PackageContext $ctx): void; + public function setPackageContext(PackageContext $ctx); /** * Get package context. * * @return PackageContext */ - public function getPackageContext(): PackageContext; + public function getPackageContext(); /** * Check if plugin should run. * @@ -89,7 +87,7 @@ public function getPackageContext(): PackageContext; * * @return boolean */ - public function shouldRun(string $package): bool; + public function shouldRun($package); /** * Check if plugin should run. * @@ -97,7 +95,7 @@ public function shouldRun(string $package): bool; * * @return boolean */ - public function shouldRunFile(string $file): bool; + public function shouldRunFile($file); /** * Get configuration key. * @@ -106,7 +104,7 @@ public function shouldRunFile(string $file): bool; * * @return mixed */ - public function getConfig(string $key, $default); + public function getConfig($key, $default); /** * Set configuration key. * @@ -115,7 +113,7 @@ public function getConfig(string $key, $default); * * @return void */ - public function setConfig(string $key, $value): void; + public function setConfig($key, $value); /** * Check if has configuration key. * @@ -123,8 +121,7 @@ public function setConfig(string $key, $value): void; * * @return mixed */ - public function hasConfig(string $key): bool; - + public function hasConfig($key); /** * Merge multiple configurations into one (or more). * @@ -132,7 +129,7 @@ public function hasConfig(string $key): bool; * * @return array[] */ - public static function mergeConfigs(array ...$configs): array; + public static function mergeConfigs(array ...$configs); /** * Split configuration. * @@ -143,5 +140,5 @@ public static function mergeConfigs(array ...$configs): array; * * @return array[] */ - public static function splitConfig(array $config): array; + public static function splitConfig(array $config); } diff --git a/src/RootNode.php b/src/RootNode.php index c5e8a9e34..5445d96d8 100644 --- a/src/RootNode.php +++ b/src/RootNode.php @@ -2,9 +2,8 @@ namespace Phabel; -use PhpParser\Node; -use PhpParser\NodeAbstract; - +use Phabel\PhpParser\Node; +use Phabel\PhpParser\NodeAbstract; /** * Root node. * @@ -24,12 +23,23 @@ public function __construct(array $stmts, array $attributes = []) $this->stmts = $stmts; parent::__construct($attributes); } - public function getSubNodeNames(): array + public function getSubNodeNames() { - return ['stmts']; + $phabelReturn = ['stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - public function getType(): string + public function getType() { - return 'rootNode'; + $phabelReturn = 'rootNode'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } } diff --git a/src/Target/Php.php b/src/Target/Php.php index f78e691c2..bdcfaeb8f 100644 --- a/src/Target/Php.php +++ b/src/Target/Php.php @@ -7,7 +7,6 @@ use Phabel\Plugin\NewFixer; use Phabel\Plugin\StmtExprWrapper; use Phabel\PluginInterface; - /** * Makes changes necessary to polyfill syntaxes of various PHP versions. * @@ -21,19 +20,11 @@ class Php extends Plugin * * @var int[] */ - const VERSIONS = [ - 56, - 70, - 71, - 72, - 73, - 74, - 80, - ]; + const VERSIONS = [56, 70, 71, 72, 73, 74, 80]; /** * Default target. */ - const DEFAULT_TARGET = PHP_MAJOR_VERSION.PHP_MINOR_VERSION; + const DEFAULT_TARGET = \PHP_MAJOR_VERSION . \PHP_MINOR_VERSION; /** * Ignore target. */ @@ -41,32 +32,43 @@ class Php extends Plugin /** * Polyfill versions. */ - const POLYFILL_VERSIONS = [ - 'symfony/polyfill-php56' => '^1.19', - 'symfony/polyfill-php70' => '^1.19', - 'symfony/polyfill-php71' => '^1.19', - 'symfony/polyfill-php72' => '^1.23', - 'symfony/polyfill-php73' => '^1.23', - 'symfony/polyfill-php74' => '^1.23', - 'symfony/polyfill-php80' => '^1.23', - 'symfony/polyfill-php81' => '^1.23', - ]; + const POLYFILL_VERSIONS = ['symfony/polyfill-php56' => '^1.19', 'symfony/polyfill-php70' => '^1.19', 'symfony/polyfill-php71' => '^1.19', 'symfony/polyfill-php72' => '^1.23', 'symfony/polyfill-php73' => '^1.23', 'symfony/polyfill-php74' => '^1.23', 'symfony/polyfill-php80' => '^1.23', 'symfony/polyfill-php81' => '^1.23']; /** * Normalize target version string. * * @param string $target * @return integer */ - public static function normalizeVersion(string $target): int + public static function normalizeVersion($target) { + if (!\is_string($target)) { + if (!(\is_string($target) || \is_object($target) && \method_exists($target, '__toString') || (\is_bool($target) || \is_numeric($target)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($target) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($target) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $target = (string) $target; + } if ($target === 'auto') { - return (int) self::DEFAULT_TARGET; + $phabelReturn = (int) self::DEFAULT_TARGET; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - if (\preg_match(":^\D*(\d+\.\d+)\..*:", $target, $matches)) { + if (\preg_match(":^\\D*(\\d+\\.\\d+)\\..*:", $target, $matches)) { $target = $matches[1]; } $target = \str_replace('.', '', $target); - return (int) (\in_array($target, self::VERSIONS) ? $target : self::DEFAULT_TARGET); + $phabelReturn = (int) (\in_array($target, self::VERSIONS) ? $target : self::DEFAULT_TARGET); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } /** * Unnormalize version string. @@ -74,10 +76,23 @@ public static function normalizeVersion(string $target): int * @param int $target * @return string */ - public static function unnormalizeVersion(int $target): string + public static function unnormalizeVersion($target) { + if (!\is_int($target)) { + if (!(\is_bool($target) || \is_numeric($target))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($target) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($target) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $target = (int) $target; + } $target = (string) $target; - return $target[0].'.'.$target[1]; + $phabelReturn = $target[0] . '.' . $target[1]; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } /** * Get PHP version range to target. @@ -85,33 +100,40 @@ public static function unnormalizeVersion(int $target): string * @param int $target * @return int[] */ - private static function getRange(int $target): array + private static function getRange($target) { + if (!\is_int($target)) { + if (!(\is_bool($target) || \is_numeric($target))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($target) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($target) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $target = (int) $target; + } $key = \array_search($target, self::VERSIONS); - return $key === false - ? self::getRange((int) self::DEFAULT_TARGET) - : \array_slice( - self::VERSIONS, - 1 + $key - ); + $phabelReturn = $key === \false ? self::getRange((int) self::DEFAULT_TARGET) : \array_slice(self::VERSIONS, 1 + $key); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - public static function getComposerRequires(array $config): array + public static function getComposerRequires(array $config) { - $target = Php::normalizeVersion($config['target'] ?? self::DEFAULT_TARGET); - $res = [ - 'php' => '>='.Php::unnormalizeVersion($target).' <'.Php::unnormalizeVersion($target+1) - ]; + $target = \Phabel\Target\Php::normalizeVersion(isset($config['target']) ? $config['target'] : self::DEFAULT_TARGET); + $res = ['php' => '>=' . \Phabel\Target\Php::unnormalizeVersion($target) . ' <' . \Phabel\Target\Php::unnormalizeVersion($target + 1)]; foreach (self::getRange($target) as $version) { - $version = "symfony/polyfill-php$version"; + $version = "symfony/polyfill-php{$version}"; $res[$version] = self::POLYFILL_VERSIONS[$version]; } - return $res; + $phabelReturn = $res; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - public static function previous(array $config): array + public static function previous(array $config) { $classes = [ComposerSanitizer::class => []]; - foreach (self::getRange((int) ($config['target'] ?? self::DEFAULT_TARGET)) as $version) { - if (!\file_exists($dir = __DIR__."/Php$version")) { + foreach (self::getRange((int) (isset($config['target']) ? $config['target'] : self::DEFAULT_TARGET)) as $version) { + if (!\file_exists($dir = __DIR__ . "/Php{$version}")) { continue; } foreach (\scandir($dir) as $file) { @@ -122,30 +144,35 @@ public static function previous(array $config): array continue; } /** @var class-string */ - $class = self::class.$version.'\\'.\basename($file, '.php'); + $class = self::class . $version . '\\' . \basename($file, '.php'); /** @var array */ - $classes[$class] = $config[$class] ?? []; + $classes[$class] = isset($config[$class]) ? $config[$class] : []; } } - return $classes; + $phabelReturn = $classes; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - public static function next(array $config): array + public static function next(array $config) { - $classes = [ - StmtExprWrapper::class => $config[StmtExprWrapper::class] ?? [], - NewFixer::class => [] - ]; - foreach (self::getRange((int) ($config['target'] ?? self::DEFAULT_TARGET)) as $version) { - if (!\file_exists(__DIR__."/Php$version")) { + $classes = [StmtExprWrapper::class => isset($config[StmtExprWrapper::class]) ? $config[StmtExprWrapper::class] : [], NewFixer::class => []]; + foreach (self::getRange((int) (isset($config['target']) ? $config['target'] : self::DEFAULT_TARGET)) as $version) { + if (!\file_exists(__DIR__ . "/Php{$version}")) { continue; } foreach (['Nested', 'Isset'] as $t) { /** @var class-string */ - $class = self::class.$version."\\$t"."ExpressionFixer"; + $class = self::class . $version . "\\{$t}" . "ExpressionFixer"; /** @var array */ - $classes[$class] = $config[$class] ?? []; + $classes[$class] = isset($config[$class]) ? $config[$class] : []; } } - return $classes; + $phabelReturn = $classes; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php56/IssetExpressionFixer.php b/src/Target/Php56/IssetExpressionFixer.php index e0a44bc3f..ed27d8978 100644 --- a/src/Target/Php56/IssetExpressionFixer.php +++ b/src/Target/Php56/IssetExpressionFixer.php @@ -3,7 +3,6 @@ namespace Phabel\Target\Php56; use Phabel\Plugin; - class IssetExpressionFixer extends Plugin { } diff --git a/src/Target/Php56/NestedExpressionFixer.php b/src/Target/Php56/NestedExpressionFixer.php index c13a2efa0..34355fa75 100644 --- a/src/Target/Php56/NestedExpressionFixer.php +++ b/src/Target/Php56/NestedExpressionFixer.php @@ -3,7 +3,6 @@ namespace Phabel\Target\Php56; use Phabel\Plugin; - class NestedExpressionFixer extends Plugin { } diff --git a/src/Target/Php70/AnonymousClassReplacer.php b/src/Target/Php70/AnonymousClassReplacer.php index f2ddabaef..9a75c4fda 100644 --- a/src/Target/Php70/AnonymousClassReplacer.php +++ b/src/Target/Php70/AnonymousClassReplacer.php @@ -9,19 +9,18 @@ use Phabel\Target\Php71\NullableType; use Phabel\Target\Php74\ArrowClosure; use Phabel\Target\Php80\UnionTypeStripper; -use PhpParser\Builder\Method; -use PhpParser\Node; -use PhpParser\Node\Expr\BinaryOp\Concat; -use PhpParser\Node\Expr\BooleanNot; -use PhpParser\Node\Expr\ClassConstFetch; -use PhpParser\Node\Expr\New_; -use PhpParser\Node\Identifier; -use PhpParser\Node\Name\FullyQualified; -use PhpParser\Node\Scalar\String_; -use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\If_; -use PhpParser\Node\Stmt\Return_; - +use Phabel\PhpParser\Builder\Method; +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Expr\BinaryOp\Concat; +use Phabel\PhpParser\Node\Expr\BooleanNot; +use Phabel\PhpParser\Node\Expr\ClassConstFetch; +use Phabel\PhpParser\Node\Expr\New_; +use Phabel\PhpParser\Node\Identifier; +use Phabel\PhpParser\Node\Name\FullyQualified; +use Phabel\PhpParser\Node\Scalar\String_; +use Phabel\PhpParser\Node\Stmt\Class_; +use Phabel\PhpParser\Node\Stmt\If_; +use Phabel\PhpParser\Node\Stmt\Return_; /** * @author Daniil Gentili * @license MIT @@ -31,8 +30,7 @@ class AnonymousClassReplacer extends Plugin /** * Anonymous class count. */ - private static int $count = 0; - + private static $count = 0; /** * Enter new. * @@ -41,7 +39,7 @@ class AnonymousClassReplacer extends Plugin * * @return void */ - public function enterNew(New_ $node, Context $ctx): void + public function enterNew(New_ $node, Context $ctx) { $classNode = $node->class; if (!$classNode instanceof Node\Stmt\Class_) { @@ -62,23 +60,13 @@ public function enterNew(New_ $node, Context $ctx): void } else { $className = new String_('class@anonymous'); } - - $name = 'PhabelAnonymousClass'.\hash('sha256', $ctx->getFile()).(self::$count++); - $classNode->stmts []= (new Method('getPhabelOriginalName')) - ->makePublic() - ->makeStatic() - ->addStmt(new Return_($className)) - ->getNode(); - $classNode->implements []= new FullyQualified(AnonymousClassInterface::class); + $name = 'PhabelAnonymousClass' . \hash('sha256', $ctx->getFile()) . self::$count++; + $classNode->stmts[] = (new Method('getPhabelOriginalName'))->makePublic()->makeStatic()->addStmt(new Return_($className))->getNode(); + $classNode->implements[] = new FullyQualified(AnonymousClassInterface::class); $classNode->name = new Identifier($name); $node->class = new Node\Name($name); - $ctx->nameResolver->enterNode($classNode); - - $classNode = new If_( - new BooleanNot(self::call('class_exists', new ClassConstFetch($node->class, new Identifier('class')))), - ['stmts' => [$classNode]] - ); + $classNode = new If_(new BooleanNot(self::call('class_exists', new ClassConstFetch($node->class, new Identifier('class')))), ['stmts' => [$classNode]]); $topClass = null; foreach ($ctx->parents as $parent) { if ($parent instanceof Class_) { @@ -91,14 +79,20 @@ public function enterNew(New_ $node, Context $ctx): void $ctx->insertBefore($node, $classNode); } } - - public static function previous(array $config): array + public static function previous(array $config) { - return [ArrowClosure::class, ReturnTypeHints::class, NullableType::class, UnionTypeStripper::class]; + $phabelReturn = [ArrowClosure::class, \Phabel\Target\Php70\ReturnTypeHints::class, NullableType::class, UnionTypeStripper::class]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public static function next(array $config): array + public static function next(array $config) { - return [StringConcatOptimizer::class]; + $phabelReturn = [StringConcatOptimizer::class]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php70/DefineArrayReplacer.php b/src/Target/Php70/DefineArrayReplacer.php index f81bab94d..185995dee 100644 --- a/src/Target/Php70/DefineArrayReplacer.php +++ b/src/Target/Php70/DefineArrayReplacer.php @@ -5,12 +5,11 @@ use Phabel\Context; use Phabel\Plugin; use Phabel\RootNode; -use PhpParser\Node; -use PhpParser\Node\Expr\Eval_; -use PhpParser\Node\Expr\FuncCall; -use PhpParser\Node\Name; -use PhpParser\Node\Stmt\Const_; - +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Expr\Eval_; +use Phabel\PhpParser\Node\Expr\FuncCall; +use Phabel\PhpParser\Node\Name; +use Phabel\PhpParser\Node\Stmt\Const_; /** * Converts define() arrays into const arrays. */ @@ -28,20 +27,15 @@ public function enter(FuncCall $node, Context $context) if (!$node->name instanceof Name || $node->name->toString() != 'define') { return null; } - $nameNode = $node->args[0]->value; $valueNode = $node->args[1]->value; - if (!$valueNode instanceof Node\Expr\Array_) { return null; } - if (!$context->parents->top() instanceof RootNode) { return self::callPoly('defineMe', ...$node->args); } - $constNode = new Node\Const_($nameNode->value, $valueNode); - return new Node\Stmt\Const_([$constNode]); } /** @@ -51,10 +45,16 @@ public function enter(FuncCall $node, Context $context) * @param array $value * @return void */ - public static function defineMe(string $name, array $value): void + public static function defineMe($name, array $value) { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $name = (string) $name; + } $name = \preg_replace("/[^A-Za-z0-9_]/", '', $name); - $value = \var_export($value, true); - eval("const $name = $value;"); + $value = \var_export($value, \true); + eval("const {$name} = {$value};"); } } diff --git a/src/Target/Php70/GroupUseReplacer.php b/src/Target/Php70/GroupUseReplacer.php index 2b206b1dd..63a80c1ca 100644 --- a/src/Target/Php70/GroupUseReplacer.php +++ b/src/Target/Php70/GroupUseReplacer.php @@ -3,11 +3,10 @@ namespace Phabel\Target\Php70; use Phabel\Plugin; -use PhpParser\Node; -use PhpParser\Node\Stmt\GroupUse; -use PhpParser\Node\Stmt\Use_; -use PhpParser\Node\Stmt\UseUse; - +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Stmt\GroupUse; +use Phabel\PhpParser\Node\Stmt\Use_; +use Phabel\PhpParser\Node\Stmt\UseUse; /** * @author Daniil Gentili * @license MIT @@ -21,13 +20,17 @@ class GroupUseReplacer extends Plugin * * @return Use_[] */ - public function leave(GroupUse $node): array + public function leave(GroupUse $node) { $nodePrefixParts = $node->prefix->parts; - - return \array_map(fn (UseUse $useNode) => $this->createUseNode($nodePrefixParts, $useNode), $node->uses); + $phabelReturn = \array_map(function (UseUse $useNode) use($nodePrefixParts) { + return $this->createUseNode($nodePrefixParts, $useNode); + }, $node->uses); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Create separate use node. * @@ -36,12 +39,14 @@ public function leave(GroupUse $node): array * * @return Use_ New use node */ - protected function createUseNode(array $nodePrefixParts, UseUse $useNode): Use_ + protected function createUseNode(array $nodePrefixParts, UseUse $useNode) { - $nodePrefixParts []= $useNode->name; - + $nodePrefixParts[] = $useNode->name; $nameNode = new Node\Name($nodePrefixParts); - - return new Use_([new UseUse($nameNode, $useNode->alias)], $useNode->type); + $phabelReturn = new Use_([new UseUse($nameNode, $useNode->alias)], $useNode->type); + if (!$phabelReturn instanceof Use_) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Use_, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php70/IssetExpressionFixer.php b/src/Target/Php70/IssetExpressionFixer.php index f854c50f8..c9212452c 100644 --- a/src/Target/Php70/IssetExpressionFixer.php +++ b/src/Target/Php70/IssetExpressionFixer.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\Plugin\IssetExpressionFixer as fixer; - /** * Expression fixer for PHP 70. */ @@ -13,358 +12,12 @@ class IssetExpressionFixer extends Plugin /** * {@inheritDoc} */ - public static function next(array $config): array + public static function next(array $config) { - return [ - fixer::class => [ - 'PhpParser\\Node\\Expr\\ArrayDimFetch' => - [ - 'var' => - [ - 'PhpParser\\Node\\Expr\\Array_' => true, - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\ConstFetch' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\New_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\Print_' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\DNumber' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\LNumber' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Line' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\ClassConstFetch' => - [ - 'class' => - [ - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\ClassConstFetch' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\FuncCall' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\MethodCall' => true, - 'PhpParser\\Node\\Expr\\New_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\PropertyFetch' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\StaticCall' => true, - 'PhpParser\\Node\\Expr\\StaticPropertyFetch' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\PropertyFetch' => - [ - 'var' => - [ - 'PhpParser\\Node\\Expr\\Array_' => true, - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\New_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\Print_' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\DNumber' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\LNumber' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Line' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\StaticPropertyFetch' => - [ - 'class' => - [ - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\ClassConstFetch' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\FuncCall' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\MethodCall' => true, - 'PhpParser\\Node\\Expr\\New_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\PropertyFetch' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\StaticCall' => true, - 'PhpParser\\Node\\Expr\\StaticPropertyFetch' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], -] - ]; + $phabelReturn = [fixer::class => ['Phabel\\PhpParser\\Node\\Expr\\ArrayDimFetch' => ['var' => ['Phabel\\PhpParser\\Node\\Expr\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ConstFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\New_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Print_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\DNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\LNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\ClassConstFetch' => ['class' => ['Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClassConstFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\FuncCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\MethodCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\New_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\PropertyFetch' => ['var' => ['Phabel\\PhpParser\\Node\\Expr\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\New_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Print_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\DNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\LNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => ['class' => ['Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClassConstFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\FuncCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\MethodCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\New_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]]]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php70/NestedExpressionFixer.php b/src/Target/Php70/NestedExpressionFixer.php index dcad14da8..c3afc665a 100644 --- a/src/Target/Php70/NestedExpressionFixer.php +++ b/src/Target/Php70/NestedExpressionFixer.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\Plugin\NestedExpressionFixer as fixer; - /** * Expression fixer for PHP 70. */ @@ -13,618 +12,12 @@ class NestedExpressionFixer extends Plugin /** * {@inheritDoc} */ - public static function next(array $config): array + public static function next(array $config) { - return [ - fixer::class => [ - 'PhpParser\\Node\\Expr\\ArrayDimFetch' => - [ - 'var' => - [ - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\Print_' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\DNumber' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\LNumber' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Line' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\ClassConstFetch' => - [ - 'class' => - [ - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\ClassConstFetch' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\FuncCall' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\MethodCall' => true, - 'PhpParser\\Node\\Expr\\New_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\PropertyFetch' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\StaticCall' => true, - 'PhpParser\\Node\\Expr\\StaticPropertyFetch' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\FuncCall' => - [ - 'name' => - [ - 'PhpParser\\Node\\Expr\\Array_' => true, - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\ClassConstFetch' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\ConstFetch' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\FuncCall' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\MethodCall' => true, - 'PhpParser\\Node\\Expr\\New_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\Print_' => true, - 'PhpParser\\Node\\Expr\\PropertyFetch' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\StaticCall' => true, - 'PhpParser\\Node\\Expr\\StaticPropertyFetch' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\DNumber' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\LNumber' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Line' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\MethodCall' => - [ - 'var' => - [ - 'PhpParser\\Node\\Expr\\Array_' => true, - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\Print_' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\DNumber' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\LNumber' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Line' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\PropertyFetch' => - [ - 'var' => - [ - 'PhpParser\\Node\\Expr\\Array_' => true, - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\Print_' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\DNumber' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\LNumber' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Line' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\StaticCall' => - [ - 'class' => - [ - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\ClassConstFetch' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\FuncCall' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\MethodCall' => true, - 'PhpParser\\Node\\Expr\\New_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\PropertyFetch' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\StaticCall' => true, - 'PhpParser\\Node\\Expr\\StaticPropertyFetch' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\StaticPropertyFetch' => - [ - 'class' => - [ - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\ClassConstFetch' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\FuncCall' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\MethodCall' => true, - 'PhpParser\\Node\\Expr\\New_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\PropertyFetch' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\StaticCall' => true, - 'PhpParser\\Node\\Expr\\StaticPropertyFetch' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], -] - ]; + $phabelReturn = [fixer::class => ['Phabel\\PhpParser\\Node\\Expr\\ArrayDimFetch' => ['var' => ['Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Print_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\DNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\LNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\ClassConstFetch' => ['class' => ['Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClassConstFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\FuncCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\MethodCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\New_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\FuncCall' => ['name' => ['Phabel\\PhpParser\\Node\\Expr\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClassConstFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ConstFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\FuncCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\MethodCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\New_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Print_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\DNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\LNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\MethodCall' => ['var' => ['Phabel\\PhpParser\\Node\\Expr\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Print_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\DNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\LNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\PropertyFetch' => ['var' => ['Phabel\\PhpParser\\Node\\Expr\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Print_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\DNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\LNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\StaticCall' => ['class' => ['Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClassConstFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\FuncCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\MethodCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\New_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => ['class' => ['Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClassConstFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\FuncCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\MethodCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\New_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]]]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php70/NullCoalesce/DisallowedExpressions.php b/src/Target/Php70/NullCoalesce/DisallowedExpressions.php index 38f324c8c..efbc81231 100644 --- a/src/Target/Php70/NullCoalesce/DisallowedExpressions.php +++ b/src/Target/Php70/NullCoalesce/DisallowedExpressions.php @@ -3,99 +3,7 @@ namespace Phabel\Target\Php70\NullCoalesce; use Phabel\Plugin; - abstract class DisallowedExpressions extends Plugin { - const EXPRESSIONS = [ - 'PhpParser\\Node\\Expr\\Array_' => true, - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ConstFetch' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\FuncCall' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\Match_' => true, - 'PhpParser\\Node\\Expr\\MethodCall' => true, - 'PhpParser\\Node\\Expr\\New_' => true, - 'PhpParser\\Node\\Expr\\NullsafeMethodCall' => true, - 'PhpParser\\Node\\Expr\\NullsafePropertyFetch' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\Print_' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\StaticCall' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\Throw_' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\YieldFrom' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\DNumber' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\LNumber' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Line' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, -]; + const EXPRESSIONS = ['Phabel\\PhpParser\\Node\\Expr\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ConstFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\FuncCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Match_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\MethodCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\New_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\NullsafeMethodCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\NullsafePropertyFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Print_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\StaticCall' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\YieldFrom' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\DNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\LNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]; } diff --git a/src/Target/Php70/NullCoalesceReplacer.php b/src/Target/Php70/NullCoalesceReplacer.php index 01263e6e6..dc56c4176 100644 --- a/src/Target/Php70/NullCoalesceReplacer.php +++ b/src/Target/Php70/NullCoalesceReplacer.php @@ -8,16 +8,15 @@ use Phabel\Target\Php74\NullCoalesceAssignment; use Phabel\Target\Php80\NullSafeTransformer; use Phabel\Tools; -use PhpParser\Node\Expr; -use PhpParser\Node\Expr\ArrayDimFetch; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\BinaryOp\BooleanAnd; -use PhpParser\Node\Expr\BinaryOp\Coalesce; -use PhpParser\Node\Expr\BinaryOp\NotIdentical; -use PhpParser\Node\Expr\Isset_; -use PhpParser\Node\Expr\PropertyFetch; -use PhpParser\Node\Expr\Ternary; - +use Phabel\PhpParser\Node\Expr; +use Phabel\PhpParser\Node\Expr\ArrayDimFetch; +use Phabel\PhpParser\Node\Expr\Assign; +use Phabel\PhpParser\Node\Expr\BinaryOp\BooleanAnd; +use Phabel\PhpParser\Node\Expr\BinaryOp\Coalesce; +use Phabel\PhpParser\Node\Expr\BinaryOp\NotIdentical; +use Phabel\PhpParser\Node\Expr\Isset_; +use Phabel\PhpParser\Node\Expr\PropertyFetch; +use Phabel\PhpParser\Node\Expr\Ternary; /** * @author Daniil Gentili * @license MIT @@ -30,15 +29,27 @@ class NullCoalesceReplacer extends Plugin * @param Expr $var * @return Expr */ - private static function &extractWorkVar(Expr &$var): Expr + private static function &extractWorkVar(Expr &$var) { if ($var instanceof ArrayDimFetch) { - return self::extractWorkVar($var->var); + $phabelReturn =& self::extractWorkVar($var->var); + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } if ($var instanceof PropertyFetch) { - return self::extractWorkVar($var->var); + $phabelReturn =& self::extractWorkVar($var->var); + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn =& $var; + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return $var; + return $phabelReturn; } /** * Replace null coalesce. @@ -47,29 +58,29 @@ private static function &extractWorkVar(Expr &$var): Expr * * @return Ternary */ - public function enter(Coalesce $node, Context $ctx): Ternary + public function enter(Coalesce $node, Context $ctx) { - if (!Tools::hasSideEffects($workVar = &self::extractWorkVar($node->left)) - && !isset(DisallowedExpressions::EXPRESSIONS[\get_class($node->left)]) - ) { - return new Ternary(new Isset_([$node->left]), $node->left, $node->right); + if (!Tools::hasSideEffects($workVar =& self::extractWorkVar($node->left)) && !isset(DisallowedExpressions::EXPRESSIONS[\get_class($node->left)])) { + $phabelReturn = new Ternary(new Isset_([$node->left]), $node->left, $node->right); + if (!$phabelReturn instanceof Ternary) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Ternary, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } $valueCopy = $workVar; - $check = new NotIdentical( - Tools::fromLiteral(null), - new Assign($workVar = $ctx->getVariable(), $valueCopy) - ); - return new Ternary( - $node->left === $workVar ? $check : new BooleanAnd( - $check, - new Isset_([$node->left]) - ), - $node->left, - $node->right - ); + $check = new NotIdentical(Tools::fromLiteral(null), new Assign($workVar = $ctx->getVariable(), $valueCopy)); + $phabelReturn = new Ternary($node->left === $workVar ? $check : new BooleanAnd($check, new Isset_([$node->left])), $node->left, $node->right); + if (!$phabelReturn instanceof Ternary) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Ternary, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - public static function withPrevious(array $config): array + public static function withPrevious(array $config) { - return [NullCoalesceAssignment::class, NullSafeTransformer::class]; + $phabelReturn = [NullCoalesceAssignment::class, NullSafeTransformer::class]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php70/Polyfill.php b/src/Target/Php70/Polyfill.php index bc10bea0f..69f2880dd 100644 --- a/src/Target/Php70/Polyfill.php +++ b/src/Target/Php70/Polyfill.php @@ -8,45 +8,52 @@ use Phabel\Target\Php; use Phabel\Target\Polyfill as TargetPolyfill; use Phabel\Tools; -use Throwable; use ValueError; - \define('BIG_ENDIAN', \pack('L', 1) === \pack('N', 1)); - /** * @author Daniil Gentili * @license MIT */ class Polyfill extends Plugin { - private const IS_WINDOWS = PHP_OS_FAMILY === 'Windows'; - public const CONSTANTS = [ - IntlChar::class => [ - 'NO_NUMERIC_VALUE' => -123456789.0 - ] - ]; - + const IS_WINDOWS = \PHP_OS_FAMILY === 'Windows'; + const CONSTANTS = [IntlChar::class => ['NO_NUMERIC_VALUE' => -123456789.0]]; // Todo: dns_get_record CAA // Todo: filters // Todo: getenv/putenv // Todo: unpack - /** * Get composer requirements. * * @return array */ - public static function getComposerRequires(array $config): array + public static function getComposerRequires(array $config) { - return [ - 'symfony/polyfill-php72' => Php::POLYFILL_VERSIONS['symfony/polyfill-php72'] - ]; + $phabelReturn = ['symfony/polyfill-php72' => Php::POLYFILL_VERSIONS['symfony/polyfill-php72']]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public static function assert($assertion, string|Throwable|null $exception = null): bool + public static function assert($assertion, $exception = null) { + if (!($exception instanceof \Exception || $exception instanceof \Error || \is_null($exception) || \is_null($exception))) { + if (!\is_string($exception)) { + if (!(\is_string($exception) || \is_object($exception) && \method_exists($exception, '__toString') || (\is_bool($exception) || \is_numeric($exception)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($exception) must be of type ?Throwable|string|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($exception) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $exception = (string) $exception; + } + } if ($assertion || Tools::ini_get('zend.assertions') !== 1) { - return true; + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } $exception = new AssertionError('assert(false)'); if (\is_null($exception)) { @@ -57,60 +64,195 @@ public static function assert($assertion, string|Throwable|null $exception = nul if (Tools::ini_get('assert.exception')) { throw $exception; } - \trigger_error("Uncaught $exception"); - return true; + \trigger_error("Uncaught {$exception}"); + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - - - public static function dirname(string $path, int $levels = 1): string + public static function dirname($path, $levels = 1) { + if (!\is_string($path)) { + if (!(\is_string($path) || \is_object($path) && \method_exists($path, '__toString') || (\is_bool($path) || \is_numeric($path)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($path) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($path) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $path = (string) $path; + } + if (!\is_int($levels)) { + if (!(\is_bool($levels) || \is_numeric($levels))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($levels) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($levels) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $levels = (int) $levels; + } if ($levels === 1) { - return \dirname($path); + $phabelReturn = \dirname($path); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } if ($levels < 1) { throw new ValueError('dirname(): Argument #2 ($levels) must be greater than or equal to 1'); } - for ($x = \strlen($path)-1; $x >= 0 && $levels > 0; $x--) { - if ($path[$x] === '/' || (self::IS_WINDOWS && $path[$x] === '\\')) { + for ($x = \strlen($path) - 1; $x >= 0 && $levels > 0; $x--) { + if ($path[$x] === '/' || self::IS_WINDOWS && $path[$x] === '\\') { --$levels; } } $path = \substr($path, \max(0, $x)); - return $path === '' ? '.' : $path; + $phabelReturn = $path === '' ? '.' : $path; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - - public static function get_defined_functions(bool $exclude_disabled = true): array + public static function get_defined_functions($exclude_disabled = \true) { + if (!\is_bool($exclude_disabled)) { + if (!(\is_bool($exclude_disabled) || \is_numeric($exclude_disabled) || \is_string($exclude_disabled))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($exclude_disabled) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($exclude_disabled) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $exclude_disabled = (bool) $exclude_disabled; + } if ($exclude_disabled) { $disabled = \explode(',', Tools::ini_get('disable_functions') ?: ''); $res = \get_defined_functions(); $res['internal'] = \array_diff($res['internal'], $disabled); - return $res; + $phabelReturn = $res; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = \get_defined_functions(); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return \get_defined_functions(); + return $phabelReturn; } - - public static function substr(string $string, int $offset, ?int $length = null): string + public static function substr($string, $offset, $length = null) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $length = (int) $length; + } + } if (\strlen($string) === $offset) { - return ''; + $phabelReturn = ''; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - return \substr($string, $offset, $length); + $phabelReturn = \substr($string, $offset, $length); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - - public static function iconv_substr(string $string, int $offset, ?int $length = null, ?string $encoding = null): string|bool + public static function iconv_substr($string, $offset, $length = null, $encoding = null) { - $encoding ??= \iconv_get_encoding('internal_encoding'); + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $length = (int) $length; + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + $encoding = isset($encoding) ? $encoding : \iconv_get_encoding('internal_encoding'); $len = \iconv_strlen($string, $encoding); if ($len === $offset) { - return ''; + $phabelReturn = ''; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $length = isset($length) ? $length : $len; + $phabelReturn = \iconv_substr($string, $offset, $length, $encoding); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } } - $length ??= $len; - return \iconv_substr($string, $offset, $length, $encoding); + return $phabelReturn; } - - public static function pack(string $format, ...$values): string + public static function pack($format, ...$values) { + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $format = (string) $format; + } $l = \strlen($format); $y = 0; $newFormat = ''; @@ -121,41 +263,48 @@ public static function pack(string $format, ...$values): string $repeater .= $format[$x]; } $x--; - $repeaterOrig = $repeater; if ($cur === 'a' || $cur === 'A' || $cur === 'h' || $cur === 'H' || $cur === '@') { $repeater = 1; } else { - $repeater = $repeater === '*' ? \count($values)-$y : (int) $repeater; + $repeater = $repeater === '*' ? \count($values) - $y : (int) $repeater; } - - if ((BIG_ENDIAN && $cur === 'g') || (!BIG_ENDIAN && $cur === 'G')) { + if (BIG_ENDIAN && $cur === 'g' || !BIG_ENDIAN && $cur === 'G') { $cur = ''; - for ($z = $y; $z < $y+$repeater; $z++) { + for ($z = $y; $z < $y + $repeater; $z++) { $cur .= 'a4'; $values[$z] = \strrev(\pack('f', $values[$z])); } $newFormat .= $cur; - } elseif ((BIG_ENDIAN && $cur === 'e') || (!BIG_ENDIAN && $cur === 'E')) { + } elseif (BIG_ENDIAN && $cur === 'e' || !BIG_ENDIAN && $cur === 'E') { $cur = ''; - for ($z = $y; $z < $y+$repeater; $z++) { + for ($z = $y; $z < $y + $repeater; $z++) { $cur .= 'a8'; $values[$z] = \strrev(\pack('d', $values[$z])); } $newFormat .= $cur; } else { - $newFormat .= $cur.$repeaterOrig; + $newFormat .= $cur . $repeaterOrig; } } - - return \pack($newFormat, ...$values); + $phabelReturn = \pack($newFormat, ...$values); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - /** * {@inheritDoc} */ - public static function withNext(array $config): array + public static function withNext(array $config) { - return [TargetPolyfill::class => [self::class => true]]; + $phabelReturn = [TargetPolyfill::class => [self::class => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php70/ReservedNameReplacer.php b/src/Target/Php70/ReservedNameReplacer.php index f256462dc..2ec6c5caf 100644 --- a/src/Target/Php70/ReservedNameReplacer.php +++ b/src/Target/Php70/ReservedNameReplacer.php @@ -3,9 +3,8 @@ namespace Phabel\Target\Php70; use Phabel\Plugin; -use PhpParser\Node; -use PhpParser\Node\Identifier; - +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Identifier; /** * @author Daniil Gentili * @license MIT @@ -15,18 +14,12 @@ class ReservedNameReplacer extends Plugin /** * {@inheritdoc} */ - public function leaveNode(Node $node): void + public function leaveNode(Node $node) { - if (!( - $node instanceof Node\Expr\MethodCall || - $node instanceof Node\Expr\StaticCall || - $node instanceof Node\Stmt\ClassMethod || - $node instanceof Node\Expr\ClassConstFetch || - $node instanceof Node\Const_ - ) || !$node->name instanceof Identifier) { + if (!($node instanceof Node\Expr\MethodCall || $node instanceof Node\Expr\StaticCall || $node instanceof Node\Stmt\ClassMethod || $node instanceof Node\Expr\ClassConstFetch || $node instanceof Node\Const_) || !$node->name instanceof Identifier) { return; } - $name = &$node->name->name; + $name =& $node->name->name; if (\in_array(\strtolower($name), ['continue', 'empty', 'use', 'default', 'echo'])) { $name .= '_'; } diff --git a/src/Target/Php70/ReturnTypeHints.php b/src/Target/Php70/ReturnTypeHints.php index 82233108d..384e2b5a9 100644 --- a/src/Target/Php70/ReturnTypeHints.php +++ b/src/Target/Php70/ReturnTypeHints.php @@ -4,19 +4,18 @@ use Phabel\Plugin; use Phabel\Plugin\TypeHintReplacer; - /** * @author Daniil Gentili * @license MIT */ class ReturnTypeHints extends Plugin { - public static function previous(array $config): array + public static function previous(array $config) { - return [ - TypeHintReplacer::class => [ - 'return' => true - ] - ]; + $phabelReturn = [TypeHintReplacer::class => ['return' => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php70/ScalarTypeHints.php b/src/Target/Php70/ScalarTypeHints.php index 2020d3d11..a2ecee875 100644 --- a/src/Target/Php70/ScalarTypeHints.php +++ b/src/Target/Php70/ScalarTypeHints.php @@ -4,19 +4,18 @@ use Phabel\Plugin; use Phabel\Plugin\TypeHintReplacer; - /** * @author Daniil Gentili * @license MIT */ class ScalarTypeHints extends Plugin { - public static function previous(array $config): array + public static function previous(array $config) { - return [ - TypeHintReplacer::class => [ - 'types' => ['int', 'float', 'string', 'bool'] - ] - ]; + $phabelReturn = [TypeHintReplacer::class => ['types' => ['int', 'float', 'string', 'bool']]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php70/SpaceshipOperatorReplacer.php b/src/Target/Php70/SpaceshipOperatorReplacer.php index 9587adb18..001f5e7d8 100644 --- a/src/Target/Php70/SpaceshipOperatorReplacer.php +++ b/src/Target/Php70/SpaceshipOperatorReplacer.php @@ -3,9 +3,8 @@ namespace Phabel\Target\Php70; use Phabel\Plugin; -use PhpParser\Node\Expr\BinaryOp\Spaceship; -use PhpParser\Node\Expr\StaticCall; - +use Phabel\PhpParser\Node\Expr\BinaryOp\Spaceship; +use Phabel\PhpParser\Node\Expr\StaticCall; /** * Polyfill spaceship operator. */ @@ -18,9 +17,13 @@ class SpaceshipOperatorReplacer extends Plugin * * @return StaticCall */ - public function enter(Spaceship $node): StaticCall + public function enter(Spaceship $node) { - return self::callPoly('spaceship', $node->left, $node->right); + $phabelReturn = self::callPoly('spaceship', $node->left, $node->right); + if (!$phabelReturn instanceof StaticCall) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type StaticCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Spacesip operator. @@ -30,8 +33,15 @@ public function enter(Spaceship $node): StaticCall * * @return integer */ - public static function spaceship($a, $b): int + public static function spaceship($a, $b) { - return $a < $b ? -1 : ($a === $b ? 0 : 1); + $phabelReturn = $a < $b ? -1 : ($a === $b ? 0 : 1); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } } diff --git a/src/Target/Php70/StrictTypesDeclareStatementRemover.php b/src/Target/Php70/StrictTypesDeclareStatementRemover.php index ff5684b32..772ce2537 100644 --- a/src/Target/Php70/StrictTypesDeclareStatementRemover.php +++ b/src/Target/Php70/StrictTypesDeclareStatementRemover.php @@ -3,22 +3,31 @@ namespace Phabel\Target\Php70; use Phabel\Plugin; -use PhpParser\Node\Stmt\Declare_; -use PhpParser\Node\Stmt\DeclareDeclare; -use PhpParser\Node\Stmt\Nop; - +use Phabel\PhpParser\Node\Stmt\Declare_; +use Phabel\PhpParser\Node\Stmt\DeclareDeclare; +use Phabel\PhpParser\Node\Stmt\Nop; /** * @author Daniil Gentili * @license MIT */ class StrictTypesDeclareStatementRemover extends Plugin { - public function leave(Declare_ $node): ?Nop + public function leave(Declare_ $node) { - $node->declares = \array_filter($node->declares, fn (DeclareDeclare $declare) => $declare->key->name !== 'strict_types'); + $node->declares = \array_filter($node->declares, function (DeclareDeclare $declare) { + return $declare->key->name !== 'strict_types'; + }); if (empty($node->declares)) { - return new Nop(); + $phabelReturn = new Nop(); + if (!($phabelReturn instanceof Nop || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Nop, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = null; + if (!($phabelReturn instanceof Nop || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Nop, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return null; + return $phabelReturn; } } diff --git a/src/Target/Php70/ThrowableReplacer.php b/src/Target/Php70/ThrowableReplacer.php index 973aabf41..0663c57ee 100644 --- a/src/Target/Php70/ThrowableReplacer.php +++ b/src/Target/Php70/ThrowableReplacer.php @@ -5,14 +5,13 @@ use Phabel\Plugin; use Phabel\Plugin\TypeHintReplacer; use Phabel\Target\Php71\MultipleCatchReplacer; -use PhpParser\Node; -use PhpParser\Node\Expr\BinaryOp\BooleanOr; -use PhpParser\Node\Expr\Instanceof_; -use PhpParser\Node\Name; -use PhpParser\Node\Name\FullyQualified; -use PhpParser\Node\Param; -use PhpParser\Node\Stmt\TryCatch; - +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Expr\BinaryOp\BooleanOr; +use Phabel\PhpParser\Node\Expr\Instanceof_; +use Phabel\PhpParser\Node\Name; +use Phabel\PhpParser\Node\Name\FullyQualified; +use Phabel\PhpParser\Node\Param; +use Phabel\PhpParser\Node\Stmt\TryCatch; /** * Replace \Throwable usages. */ @@ -25,9 +24,22 @@ class ThrowableReplacer extends Plugin * * @return boolean */ - public function shouldRunFile(string $file): bool + public function shouldRunFile($file) { - return !\str_ends_with($file, 'src/Target/Php70/ThrowableReplacer.php'); + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($file) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $file = (string) $file; + } + $phabelReturn = !\str_ends_with($file, 'src/Target/Php70/ThrowableReplacer.php'); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * Check if type string is \Throwable or Throwable. @@ -36,9 +48,22 @@ public function shouldRunFile(string $file): bool * * @return boolean */ - private static function isThrowable(string $type): bool + private static function isThrowable($type) { - return $type === \Throwable::class || $type === '\\Throwable'; + if (!\is_string($type)) { + if (!(\is_string($type) || \is_object($type) && \method_exists($type, '__toString') || (\is_bool($type) || \is_numeric($type)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($type) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $type = (string) $type; + } + $phabelReturn = $type === \Throwable::class || $type === '\\Throwable'; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * Check if is a throwable. @@ -47,12 +72,26 @@ private static function isThrowable(string $type): bool * @param mixed $class * @return boolean */ - public static function isInstanceofThrowable($obj, $class): bool + public static function isInstanceofThrowable($obj, $class) { if (\is_string($class) && self::isThrowable($class)) { - return $obj instanceof \Exception || $obj instanceof \Error; + $phabelReturn = $obj instanceof \Exception || $obj instanceof \Error; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - return $obj instanceof $class; + $phabelReturn = $obj instanceof $class; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * Split instance of \Throwable. @@ -67,10 +106,7 @@ public function enterInstanceOf(Instanceof_ $node) if (!$this->isThrowable($node->class->toString())) { return null; } - return new BooleanOr( - new Instanceof_($node->expr, new FullyQualified('Exception')), - new Instanceof_($node->expr, new FullyQualified('Error')) - ); + return new BooleanOr(new Instanceof_($node->expr, new FullyQualified('Exception')), new Instanceof_($node->expr, new FullyQualified('Error'))); } return self::callPoly('isInstanceofThrowable', $node->expr, $node->class); } @@ -81,18 +117,17 @@ public function enterInstanceOf(Instanceof_ $node) * * @return void */ - public function enterTryCatch(TryCatch $node): void + public function enterTryCatch(TryCatch $node) { foreach ($node->catches as $catch) { - $alreadyHasError = false; - $next = false; + $alreadyHasError = \false; + $next = \false; foreach ($catch->types as &$type) { - if ($type instanceof FullyQualified && - $type->getLast() === "Error") { - $alreadyHasError = true; + if ($type instanceof FullyQualified && $type->getLast() === "Error") { + $alreadyHasError = \true; } if ($this->isThrowable($type->toString())) { - $next = true; + $next = \true; $type = new FullyQualified('Exception'); } } @@ -101,14 +136,12 @@ public function enterTryCatch(TryCatch $node): void } } } - - public static function withPrevious(array $config): array + public static function withPrevious(array $config) { - return [ - TypeHintReplacer::class => [ - 'type' => [\Throwable::class] - ], - MultipleCatchReplacer::class => [] - ]; + $phabelReturn = [TypeHintReplacer::class => ['type' => [\Throwable::class]], MultipleCatchReplacer::class => []]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php71/ArrayList.php b/src/Target/Php71/ArrayList.php index c085c3de4..34f8d26aa 100644 --- a/src/Target/Php71/ArrayList.php +++ b/src/Target/Php71/ArrayList.php @@ -3,11 +3,10 @@ namespace Phabel\Target\Php71; use Phabel\Plugin; -use PhpParser\Node\Expr\Array_; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\List_; -use PhpParser\Node\Stmt\Foreach_; - +use Phabel\PhpParser\Node\Expr\Array_; +use Phabel\PhpParser\Node\Expr\Assign; +use Phabel\PhpParser\Node\Expr\List_; +use Phabel\PhpParser\Node\Stmt\Foreach_; /** * Replaces [] array list syntax. */ @@ -20,7 +19,7 @@ class ArrayList extends Plugin * * @return void */ - public function enterForeach(Foreach_ $node): void + public function enterForeach(Foreach_ $node) { if ($node->valueVar instanceof Array_) { self::replaceTypeInPlace($node->valueVar, List_::class); @@ -33,7 +32,7 @@ public function enterForeach(Foreach_ $node): void * * @return void */ - public function enterList(List_ $node): void + public function enterList(List_ $node) { foreach ($node->items as $item) { if ($item && $item->value instanceof Array_) { @@ -48,7 +47,7 @@ public function enterList(List_ $node): void * * @return void */ - public function enterAssign(Assign $node): void + public function enterAssign(Assign $node) { if ($node->var instanceof Array_) { $node->var = new List_($node->var->items); diff --git a/src/Target/Php71/ClassConstantVisibilityModifiersRemover.php b/src/Target/Php71/ClassConstantVisibilityModifiersRemover.php index ee72c6179..3fdf210f2 100644 --- a/src/Target/Php71/ClassConstantVisibilityModifiersRemover.php +++ b/src/Target/Php71/ClassConstantVisibilityModifiersRemover.php @@ -3,8 +3,7 @@ namespace Phabel\Target\Php71; use Phabel\Plugin; -use PhpParser\Node\Stmt\ClassConst; - +use Phabel\PhpParser\Node\Stmt\ClassConst; /** * Removes the class constant visibility modifiers (PHP 7.1). */ @@ -17,8 +16,9 @@ class ClassConstantVisibilityModifiersRemover extends Plugin * * @return void */ - public function enter(ClassConst $node): void + public function enter(ClassConst $node) { - $node->flags = 0; // Remove constant modifier + $node->flags = 0; + // Remove constant modifier } } diff --git a/src/Target/Php71/ClosureFromCallable.php b/src/Target/Php71/ClosureFromCallable.php index 4e6b8f742..0bc1d3661 100644 --- a/src/Target/Php71/ClosureFromCallable.php +++ b/src/Target/Php71/ClosureFromCallable.php @@ -4,56 +4,87 @@ use Closure; use Phabel\Plugin; -use PhpParser\Node\Expr; -use PhpParser\Node\Expr\StaticCall; -use PhpParser\Node\Name; +use Phabel\PhpParser\Node\Expr; +use Phabel\PhpParser\Node\Expr\StaticCall; +use Phabel\PhpParser\Node\Name; use ReflectionClass; use ReflectionFunction; - /** * Polyfills Closure::fromCallable. */ class ClosureFromCallable extends Plugin { - public function enter(StaticCall $staticCall): ?StaticCall + public function enter(StaticCall $staticCall) { if (!$staticCall->class instanceof Name || self::getFqdn($staticCall->class) !== Closure::class) { - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof StaticCall || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?StaticCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } if ($staticCall->name instanceof Expr) { - return self::callPoly('proxy', $staticCall->name, ...$staticCall->args); + $phabelReturn = self::callPoly('proxy', $staticCall->name, ...$staticCall->args); + if (!($phabelReturn instanceof StaticCall || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?StaticCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } elseif (\strtolower($staticCall->name->name) === 'fromcallable') { - return self::callPoly('fromCallable', $staticCall->args[0]); + $phabelReturn = self::callPoly('fromCallable', $staticCall->args[0]); + if (!($phabelReturn instanceof StaticCall || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?StaticCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = null; + if (!($phabelReturn instanceof StaticCall || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?StaticCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return null; + return $phabelReturn; } - - public static function proxy(string $method, ...$args) + public static function proxy($method, ...$args) { + if (!\is_string($method)) { + if (!(\is_string($method) || \is_object($method) && \method_exists($method, '__toString') || (\is_bool($method) || \is_numeric($method)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($method) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($method) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $method = (string) $method; + } if (\strtolower($method) === 'fromcallable') { return self::fromCallable($args[0]); } - return Closure::{$method}(...$args); + return \Phabel\Target\Php71\ClosureFromCallable::proxy($method, ...$args); } - /** * Create closure from callable. * * @param callable $callable * @return Closure */ - public static function fromCallable($callable): Closure + public static function fromCallable($callable) { if ($callable instanceof Closure) { - return $callable; + $phabelReturn = $callable; + if (!$phabelReturn instanceof Closure) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Closure, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } if (\is_object($callable)) { $callable = [$callable, '__invoke']; } if (\is_array($callable)) { $method = (new ReflectionClass($callable[0]))->getMethod($callable[1]); - return \is_string($callable[0]) ? $method->getClosure() : $method->getClosure($callable[0]); + $phabelReturn = \is_string($callable[0]) ? $method->getClosure() : $method->getClosure($callable[0]); + if (!$phabelReturn instanceof Closure) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Closure, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = (new ReflectionFunction($callable))->getClosure(); + if (!$phabelReturn instanceof Closure) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Closure, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return (new ReflectionFunction($callable))->getClosure(); + return $phabelReturn; } } diff --git a/src/Target/Php71/IssetExpressionFixer.php b/src/Target/Php71/IssetExpressionFixer.php index eee203aa1..735e94bc9 100644 --- a/src/Target/Php71/IssetExpressionFixer.php +++ b/src/Target/Php71/IssetExpressionFixer.php @@ -3,7 +3,6 @@ namespace Phabel\Target\Php71; use Phabel\Plugin; - class IssetExpressionFixer extends Plugin { } diff --git a/src/Target/Php71/IterableHint.php b/src/Target/Php71/IterableHint.php index 9575d01f4..a3511787f 100644 --- a/src/Target/Php71/IterableHint.php +++ b/src/Target/Php71/IterableHint.php @@ -4,19 +4,18 @@ use Phabel\Plugin; use Phabel\Plugin\TypeHintReplacer; - /** * @author Daniil Gentili * @license MIT */ class IterableHint extends Plugin { - public static function previous(array $config): array + public static function previous(array $config) { - return [ - TypeHintReplacer::class => [ - 'types' => ['iterable'] - ] - ]; + $phabelReturn = [TypeHintReplacer::class => ['types' => ['iterable']]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php71/ListExpression.php b/src/Target/Php71/ListExpression.php index bf41a5467..c1181e0e3 100644 --- a/src/Target/Php71/ListExpression.php +++ b/src/Target/Php71/ListExpression.php @@ -4,14 +4,17 @@ use Phabel\Plugin; use Phabel\Plugin\ListSplitter; - /** * Polyfills list expression return value. */ class ListExpression extends Plugin { - public static function previous(array $config): array + public static function previous(array $config) { - return [ListSplitter::class => ['parentExpr' => true]]; + $phabelReturn = [ListSplitter::class => ['parentExpr' => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php71/ListKey.php b/src/Target/Php71/ListKey.php index 67e855c72..546dac347 100644 --- a/src/Target/Php71/ListKey.php +++ b/src/Target/Php71/ListKey.php @@ -4,14 +4,17 @@ use Phabel\Plugin; use Phabel\Plugin\ListSplitter; - /** * Polyfills keyed list assignment. */ class ListKey extends Plugin { - public static function previous(array $config): array + public static function previous(array $config) { - return [ListSplitter::class => ['key' => true]]; + $phabelReturn = [ListSplitter::class => ['key' => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php71/MultipleCatchReplacer.php b/src/Target/Php71/MultipleCatchReplacer.php index aa3b1318b..8a5c4158e 100644 --- a/src/Target/Php71/MultipleCatchReplacer.php +++ b/src/Target/Php71/MultipleCatchReplacer.php @@ -3,8 +3,7 @@ namespace Phabel\Target\Php71; use Phabel\Plugin; -use PhpParser\Node\Stmt\TryCatch; - +use Phabel\PhpParser\Node\Stmt\TryCatch; /** * Replace compound catches. */ @@ -19,17 +18,17 @@ class MultipleCatchReplacer extends Plugin * * @return void */ - public function leave(TryCatch $node): void + public function leave(TryCatch $node) { $catches = []; foreach ($node->catches as $catch) { if (\count($catch->types) === 1) { - $catches []= $catch; + $catches[] = $catch; } else { foreach ($catch->types as $type) { $ncatch = clone $catch; $ncatch->types = [$type]; - $catches []= $ncatch; + $catches[] = $ncatch; } } } diff --git a/src/Target/Php71/NestedExpressionFixer.php b/src/Target/Php71/NestedExpressionFixer.php index 5b3337620..090acaea8 100644 --- a/src/Target/Php71/NestedExpressionFixer.php +++ b/src/Target/Php71/NestedExpressionFixer.php @@ -3,7 +3,6 @@ namespace Phabel\Target\Php71; use Phabel\Plugin; - class NestedExpressionFixer extends Plugin { } diff --git a/src/Target/Php71/NullableType.php b/src/Target/Php71/NullableType.php index 0db32aa0a..0a7298d77 100644 --- a/src/Target/Php71/NullableType.php +++ b/src/Target/Php71/NullableType.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\Plugin\TypeHintReplacer; - /** * Remove nullable typehint. * @@ -13,12 +12,12 @@ */ class NullableType extends Plugin { - public static function previous(array $config): array + public static function previous(array $config) { - return [ - TypeHintReplacer::class => [ - 'nullable' => true - ] - ]; + $phabelReturn = [TypeHintReplacer::class => ['nullable' => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php71/Polyfill.php b/src/Target/Php71/Polyfill.php index a5a76d9aa..cbec0aedb 100644 --- a/src/Target/Php71/Polyfill.php +++ b/src/Target/Php71/Polyfill.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\Target\Polyfill as TargetPolyfill; - /** * @author Daniil Gentili * @license MIT @@ -19,116 +18,543 @@ class Polyfill extends Plugin // Todo: grapheme_extract // Todo: getenv // Skip: output buffer functions - - public static function unpack(string $format, string $string, int $offset = 0): array|bool + public static function unpack($format, $string, $offset = 0) { - return \unpack($format, \substr($string, $offset)); + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $format = (string) $format; + } + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + $phabelReturn = \unpack($format, \substr($string, $offset)); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - public static function long2ip(int $ip): string|bool + public static function long2ip($ip) { - return \long2ip($ip); + if (!\is_int($ip)) { + if (!(\is_bool($ip) || \is_numeric($ip))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($ip) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($ip) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $ip = (int) $ip; + } + $phabelReturn = \long2ip($ip); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function file_get_contents(...$params): string|false + public static function file_get_contents(...$params) { if (isset($params[3]) && $params[3] < 0) { $f = \fopen($params[0], 'r', $params[1], $params[2]); - \fseek($f, 0, SEEK_END); - \fseek($f, \ftell($f)+$params[3], SEEK_SET); - $length = $params[4] ?? null; + \fseek($f, 0, \SEEK_END); + \fseek($f, \ftell($f) + $params[3], \SEEK_SET); + $length = isset($params[4]) ? $params[4] : null; if ($length === null) { - return \stream_get_contents($f); + $phabelReturn = \stream_get_contents($f); + if (!$phabelReturn instanceof \Phabel\Target\Php71\false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \fread($f, $length); + if (!$phabelReturn instanceof \Phabel\Target\Php71\false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \file_get_contents(...$params); + if (!$phabelReturn instanceof \Phabel\Target\Php71\false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; } - return \fread($f, $length); } - return \file_get_contents(...$params); + return $phabelReturn; } - - public static function get_headers(string $url, int $associative = 0, $context = null): array|false + public static function get_headers($url, $associative = 0, $context = null) { + if (!\is_string($url)) { + if (!(\is_string($url) || \is_object($url) && \method_exists($url, '__toString') || (\is_bool($url) || \is_numeric($url)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($url) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($url) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $url = (string) $url; + } + if (!\is_int($associative)) { + if (!(\is_bool($associative) || \is_numeric($associative))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($associative) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($associative) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $associative = (int) $associative; + } if (!$context) { - return \get_headers($url, $associative); + $phabelReturn = \get_headers($url, $associative); + if (!(\is_array($phabelReturn) || $phabelReturn instanceof \Phabel\Target\Php71\false)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - if (\file_get_contents($url, false, $context) === false) { - return false; + if (\file_get_contents($url, \false, $context) === \false) { + $phabelReturn = \false; + if (!(\is_array($phabelReturn) || $phabelReturn instanceof \Phabel\Target\Php71\false)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } if (!$associative) { - return $http_response_header; + $phabelReturn = $http_response_header; + if (!(\is_array($phabelReturn) || $phabelReturn instanceof \Phabel\Target\Php71\false)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } $headers = [$http_response_header[0]]; foreach ($http_response_header as $i => $header) { if ($i) { - [$k, $v] = \explode(":", $header, 2); + list($k, $v) = \explode(":", $header, 2); $headers[\trim($k, ' ')] = \trim($v, ' '); } } - return $headers; + $phabelReturn = $headers; + if (!(\is_array($phabelReturn) || $phabelReturn instanceof \Phabel\Target\Php71\false)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public static function substr_count(string $haystack, string $needle, int $offset = 0, ?int $length = null): int + public static function substr_count($haystack, $needle, $offset = 0, $length = null) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $haystack = (string) $haystack; + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $needle = (string) $needle; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $length = (int) $length; + } + } if ($offset < 0) { $offset = \strlen($haystack) + $offset; } if ($length === null) { - return \substr_count($haystack, $needle, $offset); + $phabelReturn = \substr_count($haystack, $needle, $offset); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } if ($length === 0) { - return \substr_count($haystack, $needle, $offset); + $phabelReturn = \substr_count($haystack, $needle, $offset); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } if ($length < 0) { $length = \strlen($haystack) - $length; } - return \substr_count($haystack, $needle, $offset); + $phabelReturn = \substr_count($haystack, $needle, $offset); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - - public static function strpos(string $haystack, string $needle, int $offset = 0): int|bool + public static function strpos($haystack, $needle, $offset = 0) { - return \strpos($haystack, $needle, $offset < 0 ? \strlen($haystack) + $offset : $offset); + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $haystack = (string) $haystack; + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $needle = (string) $needle; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + $phabelReturn = \strpos($haystack, $needle, $offset < 0 ? \strlen($haystack) + $offset : $offset); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - public static function stripos(string $haystack, string $needle, int $offset = 0): int|bool + public static function stripos($haystack, $needle, $offset = 0) { - return \stripos($haystack, $needle, $offset < 0 ? \strlen($haystack) + $offset : $offset); + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $haystack = (string) $haystack; + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $needle = (string) $needle; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + $phabelReturn = \stripos($haystack, $needle, $offset < 0 ? \strlen($haystack) + $offset : $offset); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - public static function mb_strpos(string $haystack, string $needle, int $offset = 0, ?string $encoding = null): int|bool + public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { - $encoding ??= \mb_internal_encoding(); - return \mb_strpos($haystack, $needle, $offset < 0 ? \mb_strlen($haystack, $encoding) + $offset : $offset, $encoding); + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $haystack = (string) $haystack; + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $needle = (string) $needle; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + $encoding = isset($encoding) ? $encoding : \mb_internal_encoding(); + $phabelReturn = \mb_strpos($haystack, $needle, $offset < 0 ? \mb_strlen($haystack, $encoding) + $offset : $offset, $encoding); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - public static function mb_stripos(string $haystack, string $needle, int $offset = 0, ?string $encoding = null): int|bool + public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { - $encoding ??= \mb_internal_encoding(); - return \mb_stripos($haystack, $needle, $offset < 0 ? \mb_strlen($haystack, $encoding) + $offset : $offset, $encoding); + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $haystack = (string) $haystack; + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $needle = (string) $needle; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + $encoding = isset($encoding) ? $encoding : \mb_internal_encoding(); + $phabelReturn = \mb_stripos($haystack, $needle, $offset < 0 ? \mb_strlen($haystack, $encoding) + $offset : $offset, $encoding); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - public static function mb_strimwidth(string $string, int $start, int $width, string $trim_marker = "", ?string $encoding = null): string + public static function mb_strimwidth($string, $start, $width, $trim_marker = "", $encoding = null) { - $encoding ??= \mb_internal_encoding(); + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_int($start)) { + if (!(\is_bool($start) || \is_numeric($start))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($start) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($start) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $start = (int) $start; + } + if (!\is_int($width)) { + if (!(\is_bool($width) || \is_numeric($width))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($width) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($width) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $width = (int) $width; + } + if (!\is_string($trim_marker)) { + if (!(\is_string($trim_marker) || \is_object($trim_marker) && \method_exists($trim_marker, '__toString') || (\is_bool($trim_marker) || \is_numeric($trim_marker)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($trim_marker) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($trim_marker) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $trim_marker = (string) $trim_marker; + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + $encoding = isset($encoding) ? $encoding : \mb_internal_encoding(); if ($start < 0) { $start = \mb_strlen($string, $encoding) + $start; } elseif ($width < 0) { $width = \mb_strlen($string, $encoding) + $width; } - return \mb_strimwidth($string, $start, $width, $trim_marker, $encoding); + $phabelReturn = \mb_strimwidth($string, $start, $width, $trim_marker, $encoding); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - public static function iconv_strpos(string $haystack, string $needle, int $offset = 0, ?string $encoding = null): int|bool + public static function iconv_strpos($haystack, $needle, $offset = 0, $encoding = null) { - $encoding ??= \iconv_get_encoding('internal_encoding'); - return \iconv_strpos($haystack, $needle, $offset < 0 ? \iconv_strlen($haystack, $encoding) + $offset : $offset, $encoding); + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $haystack = (string) $haystack; + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $needle = (string) $needle; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + $encoding = isset($encoding) ? $encoding : \iconv_get_encoding('internal_encoding'); + $phabelReturn = \iconv_strpos($haystack, $needle, $offset < 0 ? \iconv_strlen($haystack, $encoding) + $offset : $offset, $encoding); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - public static function grapheme_strpos(string $haystack, string $needle, int $offset = 0): int|bool + public static function grapheme_strpos($haystack, $needle, $offset = 0) { - return \grapheme_strpos($haystack, $needle, $offset < 0 ? \grapheme_strlen($haystack) + $offset : $offset); + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $haystack = (string) $haystack; + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $needle = (string) $needle; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + $phabelReturn = \grapheme_strpos($haystack, $needle, $offset < 0 ? \grapheme_strlen($haystack) + $offset : $offset); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - public static function grapheme_stripos(string $haystack, string $needle, int $offset = 0): int|bool + public static function grapheme_stripos($haystack, $needle, $offset = 0) { - return \grapheme_stripos($haystack, $needle, $offset < 0 ? \grapheme_strlen($haystack) + $offset : $offset); + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $haystack = (string) $haystack; + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $needle = (string) $needle; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + $phabelReturn = \grapheme_stripos($haystack, $needle, $offset < 0 ? \grapheme_strlen($haystack) + $offset : $offset); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - /** * {@inheritDoc} */ - public static function withNext(array $config): array + public static function withNext(array $config) { - return [TargetPolyfill::class => [self::class => true]]; + $phabelReturn = [TargetPolyfill::class => [self::class => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php71/VoidReturnType.php b/src/Target/Php71/VoidReturnType.php index 6c9c1036e..d50e069e5 100644 --- a/src/Target/Php71/VoidReturnType.php +++ b/src/Target/Php71/VoidReturnType.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\Plugin\TypeHintReplacer; - /** * Remove void return typehint. * @author Daniil Gentili @@ -12,12 +11,12 @@ */ class VoidReturnType extends Plugin { - public static function previous(array $config): array + public static function previous(array $config) { - return [ - TypeHintReplacer::class => [ - 'void' => true - ] - ]; + $phabelReturn = [TypeHintReplacer::class => ['void' => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php72/IssetExpressionFixer.php b/src/Target/Php72/IssetExpressionFixer.php index 7dd3a9198..f72a438bc 100644 --- a/src/Target/Php72/IssetExpressionFixer.php +++ b/src/Target/Php72/IssetExpressionFixer.php @@ -3,7 +3,6 @@ namespace Phabel\Target\Php72; use Phabel\Plugin; - class IssetExpressionFixer extends Plugin { } diff --git a/src/Target/Php72/NestedExpressionFixer.php b/src/Target/Php72/NestedExpressionFixer.php index 5fac75667..d7996ab50 100644 --- a/src/Target/Php72/NestedExpressionFixer.php +++ b/src/Target/Php72/NestedExpressionFixer.php @@ -3,7 +3,6 @@ namespace Phabel\Target\Php72; use Phabel\Plugin; - class NestedExpressionFixer extends Plugin { } diff --git a/src/Target/Php72/ObjectTypeHintReplacer.php b/src/Target/Php72/ObjectTypeHintReplacer.php index 418a406e2..027125a77 100644 --- a/src/Target/Php72/ObjectTypeHintReplacer.php +++ b/src/Target/Php72/ObjectTypeHintReplacer.php @@ -4,19 +4,18 @@ use Phabel\Plugin; use Phabel\Plugin\TypeHintReplacer; - /** * @author Daniil Gentili * @license MIT */ class ObjectTypeHintReplacer extends Plugin { - public static function previous(array $config): array + public static function previous(array $config) { - return [ - TypeHintReplacer::class => [ - 'types' => ['object'] - ] - ]; + $phabelReturn = [TypeHintReplacer::class => ['types' => ['object']]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php72/Polyfill.php b/src/Target/Php72/Polyfill.php index 33e1b3864..59325ec24 100644 --- a/src/Target/Php72/Polyfill.php +++ b/src/Target/Php72/Polyfill.php @@ -5,7 +5,6 @@ use __PHP_Incomplete_Class; use Phabel\Plugin; use Phabel\Target\Polyfill as TargetPolyfill; - /** * @author Daniil Gentili * @license MIT @@ -18,49 +17,170 @@ class Polyfill extends Plugin // Todo: ReflectionClass::getMethods, ReflectionClass::getProperties nullable // Todo: substr_compare // Skip PREG_UNMATCHED_AS_NULL - - public static function json_decode(string $json, ?bool $associative = null, int $depth = 512, int $flags = 0) + public static function json_decode($json, $associative = null, $depth = 512, $flags = 0) { - $associative ??= !!($flags & JSON_OBJECT_AS_ARRAY); + if (!\is_string($json)) { + if (!(\is_string($json) || \is_object($json) && \method_exists($json, '__toString') || (\is_bool($json) || \is_numeric($json)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($json) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($json) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $json = (string) $json; + } + if (!\is_null($associative)) { + if (!\is_bool($associative)) { + if (!(\is_bool($associative) || \is_numeric($associative) || \is_string($associative))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($associative) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($associative) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $associative = (bool) $associative; + } + } + if (!\is_int($depth)) { + if (!(\is_bool($depth) || \is_numeric($depth))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($depth) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($depth) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $depth = (int) $depth; + } + if (!\is_int($flags)) { + if (!(\is_bool($flags) || \is_numeric($flags))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($flags) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($flags) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $flags = (int) $flags; + } + $associative = isset($associative) ? $associative : !!($flags & \JSON_OBJECT_AS_ARRAY); return \json_decode($json, $associative, $depth, $flags); } - - public static function mb_convert_encoding(array|string $string, string $to_encoding, array|string|null $from_encoding = null): array|string|bool + public static function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { - $from_encoding ??= \mb_internal_encoding(); + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + if (!\is_array($string)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type array|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $string = (string) $string; + } + } + if (!\is_string($to_encoding)) { + if (!(\is_string($to_encoding) || \is_object($to_encoding) && \method_exists($to_encoding, '__toString') || (\is_bool($to_encoding) || \is_numeric($to_encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($to_encoding) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($to_encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $to_encoding = (string) $to_encoding; + } + if (!(\is_null($from_encoding) || \is_null($from_encoding))) { + if (!\is_string($from_encoding)) { + if (!(\is_string($from_encoding) || \is_object($from_encoding) && \method_exists($from_encoding, '__toString') || (\is_bool($from_encoding) || \is_numeric($from_encoding)))) { + if (!\is_array($from_encoding)) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($from_encoding) must be of type ?array|string|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($from_encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $from_encoding = (string) $from_encoding; + } + } + } + $from_encoding = isset($from_encoding) ? $from_encoding : \mb_internal_encoding(); if (\is_array($string)) { foreach ($string as $k => $s) { if (\is_array($from_encoding)) { - $string[$k] = self::mb_convert_encoding($s, $to_encoding, $from_encoding[$k] ?? null); + $string[$k] = self::mb_convert_encoding($s, $to_encoding, isset($from_encoding[$k]) ? $from_encoding[$k] : null); } else { $string[$k] = self::mb_convert_encoding($s, $to_encoding, $from_encoding); } } - return $string; + $phabelReturn = $string; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array|string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \mb_convert_encoding($string, $to_encoding, $from_encoding); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array|string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } else { + $phabelReturn = (bool) $phabelReturn; + } } - return \mb_convert_encoding($string, $to_encoding, $from_encoding); + return $phabelReturn; } - - public static function number_format( - float $num, - int $decimals = 0, - ?string $decimal_separator = ".", - ?string $thousands_separator = "," - ): string { + public static function number_format($num, $decimals = 0, $decimal_separator = ".", $thousands_separator = ",") + { + if (!\is_float($num)) { + if (!(\is_bool($num) || \is_numeric($num))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($num) must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($num) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $num = (float) $num; + } + if (!\is_int($decimals)) { + if (!(\is_bool($decimals) || \is_numeric($decimals))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($decimals) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decimals) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $decimals = (int) $decimals; + } + if (!\is_null($decimal_separator)) { + if (!\is_string($decimal_separator)) { + if (!(\is_string($decimal_separator) || \is_object($decimal_separator) && \method_exists($decimal_separator, '__toString') || (\is_bool($decimal_separator) || \is_numeric($decimal_separator)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($decimal_separator) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decimal_separator) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $decimal_separator = (string) $decimal_separator; + } + } + if (!\is_null($thousands_separator)) { + if (!\is_string($thousands_separator)) { + if (!(\is_string($thousands_separator) || \is_object($thousands_separator) && \method_exists($thousands_separator, '__toString') || (\is_bool($thousands_separator) || \is_numeric($thousands_separator)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($thousands_separator) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($thousands_separator) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $thousands_separator = (string) $thousands_separator; + } + } $res = \number_format($num, $decimals, $decimal_separator, $thousands_separator); - return $res === '-0' ? '0' : $res; + $phabelReturn = $res === '-0' ? '0' : $res; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - - public static function is_object($stuff): bool + public static function is_object($stuff) { - return $stuff instanceof __PHP_Incomplete_Class ? true : \is_object($stuff); + $phabelReturn = $stuff instanceof __PHP_Incomplete_Class ? \true : \is_object($stuff); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - /** * {@inheritDoc} */ - public static function withNext(array $config): array + public static function withNext(array $config) { - return [TargetPolyfill::class => [self::class => true]]; + $phabelReturn = [TargetPolyfill::class => [self::class => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php72/TypeContravariance.php b/src/Target/Php72/TypeContravariance.php index 2fd846254..323841943 100644 --- a/src/Target/Php72/TypeContravariance.php +++ b/src/Target/Php72/TypeContravariance.php @@ -5,15 +5,18 @@ use Phabel\Plugin; use Phabel\Plugin\ClassStoragePlugin; use Phabel\Target\Php72\TypeContravariance\TypeContravariance as T; - /** * @author Daniil Gentili * @license MIT */ class TypeContravariance extends Plugin { - public static function previous(array $config): array + public static function previous(array $config) { - return [ClassStoragePlugin::class => [T::class => true]]; + $phabelReturn = [ClassStoragePlugin::class => [T::class => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php72/TypeContravariance/TypeContravariance.php b/src/Target/Php72/TypeContravariance/TypeContravariance.php index 3e95c6022..521565e16 100644 --- a/src/Target/Php72/TypeContravariance/TypeContravariance.php +++ b/src/Target/Php72/TypeContravariance/TypeContravariance.php @@ -6,23 +6,22 @@ use Phabel\ClassStorage\Storage; use Phabel\ClassStorageProvider; use Phabel\Plugin\TypeHintReplacer; -use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\ClassMethod; +use Phabel\PhpParser\Node\Stmt\Class_; +use Phabel\PhpParser\Node\Stmt\ClassMethod; use SplStack; - /** * @author Daniil Gentili * @license MIT */ class TypeContravariance extends ClassStorageProvider { - public static function processClassGraph(ClassStorage $storage): bool + public static function processClassGraph(ClassStorage $storage) { - $changed = false; + $changed = \false; foreach ($storage->getClasses() as $class) { // Can override abstract methods foreach ($class->getMethods(Class_::MODIFIER_ABSTRACT) as $name => $method) { - $parentMethods = new SplStack; + $parentMethods = new SplStack(); $parentMethods->push($method); foreach ($class->getOverriddenMethods($name, Class_::MODIFIER_ABSTRACT, $method->flags & Class_::VISIBILITY_MODIFIER_MASK) as $childMethod) { $parentMethods->push($childMethod); @@ -41,10 +40,7 @@ public static function processClassGraph(ClassStorage $storage): bool if ($name === '__construct') { /** @var ClassMethod */ foreach ($class->getOverriddenMethods($name) as $childMethod) { - if ( - ($method->isPublic() && ($childMethod->isProtected() || $childMethod->isPrivate())) || - ($method->isProtected() && $childMethod->isPrivate()) - ) { + if ($method->isPublic() && ($childMethod->isProtected() || $childMethod->isPrivate()) || $method->isProtected() && $childMethod->isPrivate()) { $old = $childMethod->flags; $childMethod->flags &= ~Class_::VISIBILITY_MODIFIER_MASK; $childMethod->flags |= Class_::MODIFIER_PUBLIC; @@ -53,13 +49,13 @@ public static function processClassGraph(ClassStorage $storage): bool } continue; } - $act = \array_fill(0, \count($method->params), false); - $parentMethods = new SplStack; + $act = \array_fill(0, \count($method->params), \false); + $parentMethods = new SplStack(); $parentMethods->push($method); foreach ($class->getOverriddenMethods($name) as $childMethod) { foreach ($childMethod->params as $k => $param) { if (isset($method->params[$k]->type) && TypeHintReplacer::replaced($param->type)) { - $act[$k] = true; + $act[$k] = \true; } } $parentMethods->push($childMethod); @@ -77,14 +73,24 @@ public static function processClassGraph(ClassStorage $storage): bool } } } - return $changed; + $phabelReturn = $changed; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - /** * {@inheritDoc} */ - public static function next(array $config): array + public static function next(array $config) { - return [TypeHintReplacer::class]; + $phabelReturn = [TypeHintReplacer::class]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php73/IssetExpressionFixer.php b/src/Target/Php73/IssetExpressionFixer.php index 9be43a81b..6fcbeb667 100644 --- a/src/Target/Php73/IssetExpressionFixer.php +++ b/src/Target/Php73/IssetExpressionFixer.php @@ -3,7 +3,6 @@ namespace Phabel\Target\Php73; use Phabel\Plugin; - class IssetExpressionFixer extends Plugin { } diff --git a/src/Target/Php73/ListReference.php b/src/Target/Php73/ListReference.php index c164900be..5d80bdc79 100644 --- a/src/Target/Php73/ListReference.php +++ b/src/Target/Php73/ListReference.php @@ -4,14 +4,17 @@ use Phabel\Plugin; use Phabel\Plugin\ListSplitter; - /** * Polyfills list assignment by reference. */ class ListReference extends Plugin { - public static function previous(array $config): array + public static function previous(array $config) { - return [ListSplitter::class => ['byRef' => true]]; + $phabelReturn = [ListSplitter::class => ['byRef' => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php73/NestedExpressionFixer.php b/src/Target/Php73/NestedExpressionFixer.php index 88f0affba..72019229b 100644 --- a/src/Target/Php73/NestedExpressionFixer.php +++ b/src/Target/Php73/NestedExpressionFixer.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\Plugin\NestedExpressionFixer as fixer; - /** * Expression fixer for PHP 73. */ @@ -13,28 +12,12 @@ class NestedExpressionFixer extends Plugin /** * {@inheritDoc} */ - public static function next(array $config): array + public static function next(array $config) { - return [ - fixer::class => [ - 'PhpParser\\Node\\Expr\\Instanceof_' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Scalar\\DNumber' => true, - 'PhpParser\\Node\\Scalar\\LNumber' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Line' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], -] - ]; + $phabelReturn = [fixer::class => ['Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => ['expr' => ['Phabel\\PhpParser\\Node\\Scalar\\DNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\LNumber' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]]]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php73/Polyfill.php b/src/Target/Php73/Polyfill.php index 6e7634a39..663b282ea 100644 --- a/src/Target/Php73/Polyfill.php +++ b/src/Target/Php73/Polyfill.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\Target\Polyfill as TargetPolyfill; - /** * @author Daniil Gentili * @license MIT @@ -14,32 +13,65 @@ class Polyfill extends Plugin // Skip apache_request_headers // Todo: setrawcookie // Todo: password_hash - - public static function getComposerRequires(array $config): array + public static function getComposerRequires(array $config) { - return ['ralouphie/getallheaders' => '^3|^2']; + $phabelReturn = ['ralouphie/getallheaders' => '^3|^2']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public static function array_push(array &$array, ...$values): int + public static function array_push(array &$array, ...$values) { if (\count($values) === 0) { - return \count($array); + $phabelReturn = \count($array); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - return \array_push($array, ...$values); + $phabelReturn = \array_push($array, ...$values); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - public static function array_unshift(array &$array, ...$values): int + public static function array_unshift(array &$array, ...$values) { if (\count($values) === 0) { - return \count($array); + $phabelReturn = \count($array); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; + } + $phabelReturn = \array_unshift($array, ...$values); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; } - return \array_unshift($array, ...$values); + return $phabelReturn; } - /** * {@inheritDoc} */ - public static function withNext(array $config): array + public static function withNext(array $config) { - return [TargetPolyfill::class => [self::class => true]]; + $phabelReturn = [TargetPolyfill::class => [self::class => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php74/ArrayUnpack.php b/src/Target/Php74/ArrayUnpack.php index 90b54e77e..54447e27d 100644 --- a/src/Target/Php74/ArrayUnpack.php +++ b/src/Target/Php74/ArrayUnpack.php @@ -4,51 +4,70 @@ use Phabel\Context; use Phabel\Plugin; -use PhpParser\Node\Arg; -use PhpParser\Node\Expr\Array_; -use PhpParser\Node\Expr\ArrayItem; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\FuncCall; -use PhpParser\Node\Expr\List_; -use PhpParser\Node\Stmt\Foreach_; - +use Phabel\PhpParser\Node\Arg; +use Phabel\PhpParser\Node\Expr\Array_; +use Phabel\PhpParser\Node\Expr\ArrayItem; +use Phabel\PhpParser\Node\Expr\Assign; +use Phabel\PhpParser\Node\Expr\FuncCall; +use Phabel\PhpParser\Node\Expr\List_; +use Phabel\PhpParser\Node\Stmt\Foreach_; /** * @author Daniil Gentili * @license MIT */ class ArrayUnpack extends Plugin { - public function enter(Array_ $array, Context $context): ?FuncCall + public function enter(Array_ $array, Context $context) { foreach ($context->parents as $parent) { if ($parent instanceof Array_) { continue; } if ($parent instanceof List_) { - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof FuncCall || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?FuncCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** @var string */ $key = $parent->getAttribute('currentNode'); if ($parent instanceof Assign && $key === 'var') { - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof FuncCall || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?FuncCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } if ($parent instanceof Foreach_ && $key === 'valueVar') { - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof FuncCall || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?FuncCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } break; } - $hasUnpack = false; + $hasUnpack = \false; foreach ($array->items as $item) { if (!$item) { - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof FuncCall || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?FuncCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } if ($item->unpack) { - $hasUnpack = true; + $hasUnpack = \true; break; } } if (!$hasUnpack) { - return null; + $phabelReturn = null; + if (!($phabelReturn instanceof FuncCall || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?FuncCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } $args = []; $current = new Array_(); @@ -56,17 +75,21 @@ public function enter(Array_ $array, Context $context): ?FuncCall foreach ($array->items as $item) { if ($item->unpack) { if ($current->items) { - $args []= new Arg($current); + $args[] = new Arg($current); $current = new Array_(); } - $args []= new Arg($item->value); + $args[] = new Arg($item->value); } else { - $current->items []= $item; + $current->items[] = $item; } } if ($current->items) { - $args []= new Arg($current); + $args[] = new Arg($current); + } + $phabelReturn = Plugin::call("array_merge", ...$args); + if (!($phabelReturn instanceof FuncCall || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?FuncCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return Plugin::call("array_merge", ...$args); + return $phabelReturn; } } diff --git a/src/Target/Php74/ArrowClosure.php b/src/Target/Php74/ArrowClosure.php index 759763596..c2d8a2098 100644 --- a/src/Target/Php74/ArrowClosure.php +++ b/src/Target/Php74/ArrowClosure.php @@ -5,12 +5,11 @@ use Phabel\Context; use Phabel\Plugin; use Phabel\Plugin\VariableFinder; -use PhpParser\Node\Expr\ArrowFunction; -use PhpParser\Node\Expr\Closure; -use PhpParser\Node\Expr\Variable; -use PhpParser\Node\Param; -use PhpParser\Node\Stmt\Return_; - +use Phabel\PhpParser\Node\Expr\ArrowFunction; +use Phabel\PhpParser\Node\Expr\Closure; +use Phabel\PhpParser\Node\Expr\Variable; +use Phabel\PhpParser\Node\Param; +use Phabel\PhpParser\Node\Stmt\Return_; /** * Turn an arrow function into a closure. */ @@ -23,7 +22,7 @@ class ArrowClosure extends Plugin * * @return Closure */ - public function enter(ArrowFunction $func, Context $context): Closure + public function enter(ArrowFunction $func, Context $context) { /** @var array */ $nodes = []; @@ -36,21 +35,17 @@ public function enter(ArrowFunction $func, Context $context): Closure /** @var array */ $params = []; /** @var Param */ - foreach ($nodes['params'] ?? [] as $param) { + foreach (isset($nodes['params']) ? $nodes['params'] : [] as $param) { if ($param->var instanceof Variable) { /** @var string $param->var->name */ - $params[$param->var->name] = true; + $params[$param->var->name] = \true; } } - $nodes['uses'] = \array_values( - \array_intersect_key( - \array_diff_key( - VariableFinder::find($func->expr), - $params, - ), - $context->variables->top()->getVars() - ) - ); - return new Closure($nodes, $func->getAttributes()); + $nodes['uses'] = \array_values(\array_intersect_key(\array_diff_key(VariableFinder::find($func->expr), $params), $context->variables->top()->getVars())); + $phabelReturn = new Closure($nodes, $func->getAttributes()); + if (!$phabelReturn instanceof Closure) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Closure, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php74/IssetExpressionFixer.php b/src/Target/Php74/IssetExpressionFixer.php index 318138ac5..eedf3e375 100644 --- a/src/Target/Php74/IssetExpressionFixer.php +++ b/src/Target/Php74/IssetExpressionFixer.php @@ -3,7 +3,6 @@ namespace Phabel\Target\Php74; use Phabel\Plugin; - class IssetExpressionFixer extends Plugin { } diff --git a/src/Target/Php74/NestedExpressionFixer.php b/src/Target/Php74/NestedExpressionFixer.php index 78576914e..6fe07b3e7 100644 --- a/src/Target/Php74/NestedExpressionFixer.php +++ b/src/Target/Php74/NestedExpressionFixer.php @@ -3,7 +3,6 @@ namespace Phabel\Target\Php74; use Phabel\Plugin; - class NestedExpressionFixer extends Plugin { } diff --git a/src/Target/Php74/NullCoalesceAssignment.php b/src/Target/Php74/NullCoalesceAssignment.php index 2dbb44102..70da00083 100644 --- a/src/Target/Php74/NullCoalesceAssignment.php +++ b/src/Target/Php74/NullCoalesceAssignment.php @@ -3,18 +3,21 @@ namespace Phabel\Target\Php74; use Phabel\Plugin; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\AssignOp\Coalesce; -use PhpParser\Node\Expr\BinaryOp\Coalesce as BinaryOpCoalesce; - +use Phabel\PhpParser\Node\Expr\Assign; +use Phabel\PhpParser\Node\Expr\AssignOp\Coalesce; +use Phabel\PhpParser\Node\Expr\BinaryOp\Coalesce as BinaryOpCoalesce; /** * @author Daniil Gentili * @license MIT */ class NullCoalesceAssignment extends Plugin { - public function enter(Coalesce $coalesce): Assign + public function enter(Coalesce $coalesce) { - return new Assign($coalesce->var, new BinaryOpCoalesce($coalesce->var, $coalesce->expr), $coalesce->getAttributes()); + $phabelReturn = new Assign($coalesce->var, new BinaryOpCoalesce($coalesce->var, $coalesce->expr), $coalesce->getAttributes()); + if (!$phabelReturn instanceof Assign) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Assign, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php74/Polyfill.php b/src/Target/Php74/Polyfill.php index 38b6410f3..edb5dad8b 100644 --- a/src/Target/Php74/Polyfill.php +++ b/src/Target/Php74/Polyfill.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\Target\Polyfill as TargetPolyfill; - /** * @author Daniil Gentili * @license MIT @@ -12,28 +11,58 @@ class Polyfill extends Plugin { // Todo: gmmktime, mktime - - public static function array_filter(array $array, ?callable $callback = null, int $mode = 0): array + public static function array_filter(array $array, $callback = null, $mode = 0) { - $callback ??= fn ($v) => $v; - return \array_filter($array, $callback, $mode); + if (!(\is_callable($callback) || \is_null($callback))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($callback) must be of type ?callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($callback) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($mode) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $mode = (int) $mode; + } + $callback = isset($callback) ? $callback : function ($v) { + return $v; + }; + $phabelReturn = \array_filter($array, $callback, $mode); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public static function array_splice( - array &$array, - int $offset, - ?int $length = null, - mixed $replacement = [] - ): array { - $length ??= \max(\count($array) - $offset, 0); - return \array_splice($array, $offset, $length, $replacement); + public static function array_splice(array &$array, $offset, $length = null, mixed $replacement = []) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $length = (int) $length; + } + } + $length = isset($length) ? $length : \max(\count($array) - $offset, 0); + $phabelReturn = \array_splice($array, $offset, $length, $replacement); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * {@inheritDoc} */ - public static function withNext(array $config): array + public static function withNext(array $config) { - return [TargetPolyfill::class => [self::class => true]]; + $phabelReturn = [TargetPolyfill::class => [self::class => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php74/Serializable.php b/src/Target/Php74/Serializable.php index d9500b4f4..f191c74b9 100644 --- a/src/Target/Php74/Serializable.php +++ b/src/Target/Php74/Serializable.php @@ -4,45 +4,45 @@ use Phabel\Context; use Phabel\Plugin; -use PhpParser\Node\Identifier; -use PhpParser\Node\Name\FullyQualified; -use PhpParser\Node\Stmt\Class_; -use PhpParser\Node\Stmt\ClassMethod; +use Phabel\PhpParser\Node\Identifier; +use Phabel\PhpParser\Node\Name\FullyQualified; +use Phabel\PhpParser\Node\Stmt\Class_; +use Phabel\PhpParser\Node\Stmt\ClassMethod; use Serializable as GlobalSerializable; - /** * Implement __serialize and __unserialize. */ class Serializable extends Plugin -{/* - public function enter(Class_ $class, Context $context): void - { - /** @var array */ - /* - $methods = []; - foreach ($class->stmts as $stmt) { - if ($stmt instanceof ClassMethod) { - $name = $stmt->name->toLowerString(); - $methods[$name] = $stmt; - } - } - - if (!isset($methods['__serialize']) && !isset($methods['__unserialize'])) { - return; - } - foreach ($class->implements as $name) { - $resolved = $context->getNameContext()->getResolvedClassName($name); - if ($resolved->toLowerString() === 'serializable' || $name->toLowerString() === 'serializable') { - return; // Already implements - } - } - if (isset($methods['__sleep'])) { - $methods['__sleep']->name = new Identifier('__phabelSleep'); - } - if (isset($methods['__wakeup'])) { - $methods['__wakeup']->name = new Identifier('__phabelWakeup'); - } - - $class->implements []= new FullyQualified(GlobalSerializable::class); - }*/ +{ + /* + public function enter(Class_ $class, Context $context): void + { + /** @var array */ + /* + $methods = []; + foreach ($class->stmts as $stmt) { + if ($stmt instanceof ClassMethod) { + $name = $stmt->name->toLowerString(); + $methods[$name] = $stmt; + } + } + + if (!isset($methods['__serialize']) && !isset($methods['__unserialize'])) { + return; + } + foreach ($class->implements as $name) { + $resolved = $context->getNameContext()->getResolvedClassName($name); + if ($resolved->toLowerString() === 'serializable' || $name->toLowerString() === 'serializable') { + return; // Already implements + } + } + if (isset($methods['__sleep'])) { + $methods['__sleep']->name = new Identifier('__phabelSleep'); + } + if (isset($methods['__wakeup'])) { + $methods['__wakeup']->name = new Identifier('__phabelWakeup'); + } + + $class->implements []= new FullyQualified(GlobalSerializable::class); + }*/ } diff --git a/src/Target/Php74/TypeContracovariance.php b/src/Target/Php74/TypeContracovariance.php index 1ca76a014..7f08d312f 100644 --- a/src/Target/Php74/TypeContracovariance.php +++ b/src/Target/Php74/TypeContracovariance.php @@ -5,15 +5,18 @@ use Phabel\Plugin; use Phabel\Plugin\ClassStoragePlugin; use Phabel\Target\Php74\TypeContracovariance\TypeContracovariance as T; - /** * @author Daniil Gentili * @license MIT */ class TypeContracovariance extends Plugin { - public static function previous(array $config): array + public static function previous(array $config) { - return [ClassStoragePlugin::class => [T::class => true]]; + $phabelReturn = [ClassStoragePlugin::class => [T::class => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php74/TypeContracovariance/TypeContracovariance.php b/src/Target/Php74/TypeContracovariance/TypeContracovariance.php index 1971a45d5..9c73e2e02 100644 --- a/src/Target/Php74/TypeContracovariance/TypeContracovariance.php +++ b/src/Target/Php74/TypeContracovariance/TypeContracovariance.php @@ -7,33 +7,32 @@ use Phabel\ClassStorageProvider; use Phabel\Plugin\TypeHintReplacer; use SplStack; - /** * @author Daniil Gentili * @license MIT */ class TypeContracovariance extends ClassStorageProvider { - public static function processClassGraph(ClassStorage $storage): bool + public static function processClassGraph(ClassStorage $storage) { - $changed = false; + $changed = \false; foreach ($storage->getClasses() as $class) { // Contravariance: a parameter type can be less specific (more types) in a child method // Covariance: a child method can return a more specific (less types) type foreach ($class->getMethods() as $name => $method) { - $actReturn = false; - $act = \array_fill(0, \count($method->params), false); - $parentMethods = new SplStack; + $actReturn = \false; + $act = \array_fill(0, \count($method->params), \false); + $parentMethods = new SplStack(); $parentMethods->push($method); foreach ($class->getOverriddenMethods($name) as $childMethod) { $childClass = $childMethod->getAttribute(Storage::STORAGE_KEY); foreach ($childMethod->params as $k => $param) { if (isset($method->params[$k]) && $storage->compare($param->type, $method->params[$k]->type, $childClass, $class) > 0) { - $act[$k] = true; + $act[$k] = \true; } } if ($storage->compare($childMethod->returnType, $method->returnType, $childClass, $class) < 0) { - $actReturn = true; + $actReturn = \true; } $parentMethods->push($childMethod); } @@ -53,14 +52,24 @@ public static function processClassGraph(ClassStorage $storage): bool } } } - return $changed; + $phabelReturn = $changed; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - /** * {@inheritDoc} */ - public static function next(array $config): array + public static function next(array $config) { - return [TypeHintReplacer::class]; + $phabelReturn = [TypeHintReplacer::class]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php74/TypedProperty.php b/src/Target/Php74/TypedProperty.php index 1d6fb4a8e..78c7160af 100644 --- a/src/Target/Php74/TypedProperty.php +++ b/src/Target/Php74/TypedProperty.php @@ -3,15 +3,14 @@ namespace Phabel\Target\Php74; use Phabel\Plugin; -use PhpParser\Node\Stmt\ClassLike; -use PhpParser\Node\Stmt\Property; - +use Phabel\PhpParser\Node\Stmt\ClassLike; +use Phabel\PhpParser\Node\Stmt\Property; /** * Implement typed properties. */ class TypedProperty extends Plugin { - public function enter(ClassLike $class): void + public function enter(ClassLike $class) { foreach ($class->stmts as $stmt) { if ($stmt instanceof Property && $stmt->type) { diff --git a/src/Target/Php80/IssetExpressionFixer.php b/src/Target/Php80/IssetExpressionFixer.php index 72d57c017..fd2f8a63a 100644 --- a/src/Target/Php80/IssetExpressionFixer.php +++ b/src/Target/Php80/IssetExpressionFixer.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\Plugin\IssetExpressionFixer as fixer; - /** * Expression fixer for PHP 80. */ @@ -13,48 +12,12 @@ class IssetExpressionFixer extends Plugin /** * {@inheritDoc} */ - public static function next(array $config): array + public static function next(array $config) { - return [ - fixer::class => [ - 'PhpParser\\Node\\Expr\\ArrayDimFetch' => - [ - 'var' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - 'dim' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\PropertyFetch' => - [ - 'var' => - [ - 'PhpParser\\Node\\Expr\\ConstFetch' => true, - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - 'name' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\StaticPropertyFetch' => - [ - 'name' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Variable' => - [ - 'name' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], -] - ]; + $phabelReturn = [fixer::class => ['Phabel\\PhpParser\\Node\\Expr\\ArrayDimFetch' => ['var' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true], 'dim' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\PropertyFetch' => ['var' => ['Phabel\\PhpParser\\Node\\Expr\\ConstFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true], 'name' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => ['name' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Variable' => ['name' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]]]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php80/MatchTransformer.php b/src/Target/Php80/MatchTransformer.php index 6758dd63d..a52e61b90 100644 --- a/src/Target/Php80/MatchTransformer.php +++ b/src/Target/Php80/MatchTransformer.php @@ -5,37 +5,29 @@ use Phabel\Context; use Phabel\Plugin; use Phabel\Plugin\VariableFinder; -use PhpParser\Node\Arg; -use PhpParser\Node\Expr\BinaryOp\Concat; -use PhpParser\Node\Expr\BinaryOp\Identical; -use PhpParser\Node\Expr\Closure; -use PhpParser\Node\Expr\FuncCall; -use PhpParser\Node\Expr\Match_; -use PhpParser\Node\Expr\New_; -use PhpParser\Node\Name\FullyQualified; -use PhpParser\Node\Param; -use PhpParser\Node\Scalar\String_; -use PhpParser\Node\Stmt\Else_; -use PhpParser\Node\Stmt\ElseIf_; -use PhpParser\Node\Stmt\If_; -use PhpParser\Node\Stmt\Return_; -use PhpParser\Node\Stmt\Throw_; - +use Phabel\PhpParser\Node\Arg; +use Phabel\PhpParser\Node\Expr\BinaryOp\Concat; +use Phabel\PhpParser\Node\Expr\BinaryOp\Identical; +use Phabel\PhpParser\Node\Expr\Closure; +use Phabel\PhpParser\Node\Expr\FuncCall; +use Phabel\PhpParser\Node\Expr\Match_; +use Phabel\PhpParser\Node\Expr\New_; +use Phabel\PhpParser\Node\Name\FullyQualified; +use Phabel\PhpParser\Node\Param; +use Phabel\PhpParser\Node\Scalar\String_; +use Phabel\PhpParser\Node\Stmt\Else_; +use Phabel\PhpParser\Node\Stmt\ElseIf_; +use Phabel\PhpParser\Node\Stmt\If_; +use Phabel\PhpParser\Node\Stmt\Return_; +use Phabel\PhpParser\Node\Stmt\Throw_; /** * Polyfill match expression. */ class MatchTransformer extends Plugin { - public function enter(Match_ $match, Context $context): FuncCall + public function enter(Match_ $match, Context $context) { - $closure = new Closure( - [ - 'params' => [new Param($var = $context->getVariable())], - 'uses' => \array_values(VariableFinder::find($match, true)) - ] - ); - - + $closure = new Closure(['params' => [new Param($var = $context->getVariable())], 'uses' => \array_values(VariableFinder::find($match, \true))]); $cases = []; $default = null; foreach ($match->arms as $arm) { @@ -44,34 +36,27 @@ public function enter(Match_ $match, Context $context): FuncCall continue; } foreach ($arm->conds as $cond) { - $cases []= [new Identical($var, $cond), new Return_($arm->body)]; + $cases[] = [new Identical($var, $cond), new Return_($arm->body)]; } } if (!$default) { $string = new Concat(new String_("Unhandled match value of type "), self::call('get_debug_type', $var)); $default = new Throw_(new New_(new FullyQualified(\UnhandledMatchError::class), [new Arg($string)])); } - if (empty($cases)) { $closure->stmts = [$default]; } else { - [$ifCond, $ifBody] = \array_shift($cases); + list($ifCond, $ifBody) = \array_shift($cases); foreach ($cases as &$case) { - [$cond, $body] = $case; + list($cond, $body) = $case; $case = new ElseIf_($cond, [$body]); } - $closure->stmts = [ - new If_( - $ifCond, - [ - 'stmts' => [$ifBody], - 'elseifs' => $cases, - 'else' => new Else_([$default]) - ] - ) - ]; + $closure->stmts = [new If_($ifCond, ['stmts' => [$ifBody], 'elseifs' => $cases, 'else' => new Else_([$default])])]; } - - return new FuncCall($closure, [new Arg($match->cond)]); + $phabelReturn = new FuncCall($closure, [new Arg($match->cond)]); + if (!$phabelReturn instanceof FuncCall) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type FuncCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php80/NestedExpressionFixer.php b/src/Target/Php80/NestedExpressionFixer.php index d5aef6930..b8305bf78 100644 --- a/src/Target/Php80/NestedExpressionFixer.php +++ b/src/Target/Php80/NestedExpressionFixer.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\Plugin\NestedExpressionFixer as fixer; - /** * Expression fixer for PHP 80. */ @@ -13,661 +12,12 @@ class NestedExpressionFixer extends Plugin /** * {@inheritDoc} */ - public static function next(array $config): array + public static function next(array $config) { - return [ - fixer::class => [ - 'PhpParser\\Node\\Expr\\ArrayDimFetch' => - [ - 'var' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - 'dim' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Assign' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BitwiseNot' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BooleanNot' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Clone_' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Empty_' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\ErrorSuppress' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Eval_' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\FuncCall' => - [ - 'name' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Instanceof_' => - [ - 'class' => - [ - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\New_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\YieldFrom' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\MethodCall' => - [ - 'var' => - [ - 'PhpParser\\Node\\Expr\\ConstFetch' => true, - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\New_' => - [ - 'class' => - [ - 'PhpParser\\Node\\Expr\\Assign' => true, - 'PhpParser\\Node\\Expr\\AssignRef' => true, - 'PhpParser\\Node\\Expr\\BitwiseNot' => true, - 'PhpParser\\Node\\Expr\\BooleanNot' => true, - 'PhpParser\\Node\\Expr\\Clone_' => true, - 'PhpParser\\Node\\Expr\\Closure' => true, - 'PhpParser\\Node\\Expr\\ClosureUse' => true, - 'PhpParser\\Node\\Expr\\Empty_' => true, - 'PhpParser\\Node\\Expr\\ErrorSuppress' => true, - 'PhpParser\\Node\\Expr\\Eval_' => true, - 'PhpParser\\Node\\Expr\\Include_' => true, - 'PhpParser\\Node\\Expr\\Instanceof_' => true, - 'PhpParser\\Node\\Expr\\Isset_' => true, - 'PhpParser\\Node\\Expr\\New_' => true, - 'PhpParser\\Node\\Expr\\PostDec' => true, - 'PhpParser\\Node\\Expr\\PostInc' => true, - 'PhpParser\\Node\\Expr\\PreDec' => true, - 'PhpParser\\Node\\Expr\\PreInc' => true, - 'PhpParser\\Node\\Expr\\ShellExec' => true, - 'PhpParser\\Node\\Expr\\Ternary' => true, - 'PhpParser\\Node\\Expr\\UnaryMinus' => true, - 'PhpParser\\Node\\Expr\\UnaryPlus' => true, - 'PhpParser\\Node\\Expr\\YieldFrom' => true, - 'PhpParser\\Node\\Expr\\Yield_' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => true, - 'PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => true, - 'PhpParser\\Node\\Expr\\Cast\\Array_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Double' => true, - 'PhpParser\\Node\\Expr\\Cast\\Int_' => true, - 'PhpParser\\Node\\Expr\\Cast\\Object_' => true, - 'PhpParser\\Node\\Expr\\Cast\\String_' => true, - 'PhpParser\\Node\\Scalar\\Encapsed' => true, - 'PhpParser\\Node\\Scalar\\String_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Class_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Dir' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\File' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Function_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Method' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => true, - 'PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Print_' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\PropertyFetch' => - [ - 'var' => - [ - 'PhpParser\\Node\\Expr\\ConstFetch' => true, - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - 'name' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\StaticPropertyFetch' => - [ - 'name' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Ternary' => - [ - 'if' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - 'else' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Throw_' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\UnaryMinus' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\UnaryPlus' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Variable' => - [ - 'name' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\YieldFrom' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Yield_' => - [ - 'value' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - 'key' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\Concat' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\Div' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\Minus' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\Mod' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\Mul' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\Plus' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\Pow' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Concat' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Div' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Equal' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Greater' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Identical' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Minus' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Mod' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Mul' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Plus' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Pow' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => - [ - 'right' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Cast\\Array_' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Cast\\Bool_' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Cast\\Double' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Cast\\Int_' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Cast\\Object_' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], - 'PhpParser\\Node\\Expr\\Cast\\String_' => - [ - 'expr' => - [ - 'PhpParser\\Node\\Expr\\Throw_' => true, - ], - ], -] - ]; + $phabelReturn = [fixer::class => ['Phabel\\PhpParser\\Node\\Expr\\ArrayDimFetch' => ['var' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true], 'dim' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Assign' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\FuncCall' => ['name' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => ['class' => ['Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\New_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\YieldFrom' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\MethodCall' => ['var' => ['Phabel\\PhpParser\\Node\\Expr\\ConstFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\New_' => ['class' => ['Phabel\\PhpParser\\Node\\Expr\\Assign' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignRef' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BitwiseNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BooleanNot' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Clone_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Closure' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ClosureUse' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Empty_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ErrorSuppress' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Eval_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Include_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Instanceof_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Isset_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\New_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PostInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreDec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\PreInc' => \true, 'Phabel\\PhpParser\\Node\\Expr\\ShellExec' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\YieldFrom' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => \true, 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\Encapsed' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\String_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\File' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => \true, 'Phabel\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Print_' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\PropertyFetch' => ['var' => ['Phabel\\PhpParser\\Node\\Expr\\ConstFetch' => \true, 'Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true], 'name' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => ['name' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Ternary' => ['if' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true], 'else' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Throw_' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\UnaryMinus' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\UnaryPlus' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Variable' => ['name' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\YieldFrom' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Yield_' => ['value' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true], 'key' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Div' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => ['right' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Array_' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Bool_' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Double' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Int_' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Cast\\Object_' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]], 'Phabel\\PhpParser\\Node\\Expr\\Cast\\String_' => ['expr' => ['Phabel\\PhpParser\\Node\\Expr\\Throw_' => \true]]]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php80/NullSafe/NullSafe.php b/src/Target/Php80/NullSafe/NullSafe.php index 9fdf82526..149fe994e 100644 --- a/src/Target/Php80/NullSafe/NullSafe.php +++ b/src/Target/Php80/NullSafe/NullSafe.php @@ -7,7 +7,7 @@ */ class NullSafe { - public static self $singleton; + public static $singleton; /** * Null. * @@ -38,5 +38,4 @@ public function __get($name) { } } - -NullSafe::$singleton = new NullSafe; +\Phabel\Target\Php80\NullSafe\NullSafe::$singleton = new \Phabel\Target\Php80\NullSafe\NullSafe(); diff --git a/src/Target/Php80/NullSafeTransformer.php b/src/Target/Php80/NullSafeTransformer.php index efa3ebabf..a664c9585 100644 --- a/src/Target/Php80/NullSafeTransformer.php +++ b/src/Target/Php80/NullSafeTransformer.php @@ -5,16 +5,15 @@ use Phabel\Plugin; use Phabel\Plugin\NestedExpressionFixer; use Phabel\Target\Php80\NullSafe\NullSafe; -use PhpParser\Node\Expr\BinaryOp\Coalesce; -use PhpParser\Node\Expr\MethodCall; -use PhpParser\Node\Expr\New_; -use PhpParser\Node\Expr\NullsafeMethodCall; -use PhpParser\Node\Expr\NullsafePropertyFetch; -use PhpParser\Node\Expr\PropertyFetch; -use PhpParser\Node\Expr\StaticPropertyFetch; -use PhpParser\Node\Name\FullyQualified; -use PhpParser\Node\Param; - +use Phabel\PhpParser\Node\Expr\BinaryOp\Coalesce; +use Phabel\PhpParser\Node\Expr\MethodCall; +use Phabel\PhpParser\Node\Expr\New_; +use Phabel\PhpParser\Node\Expr\NullsafeMethodCall; +use Phabel\PhpParser\Node\Expr\NullsafePropertyFetch; +use Phabel\PhpParser\Node\Expr\PropertyFetch; +use Phabel\PhpParser\Node\Expr\StaticPropertyFetch; +use Phabel\PhpParser\Node\Name\FullyQualified; +use Phabel\PhpParser\Node\Param; /** * Polyfill nullsafe expressions. */ @@ -26,24 +25,34 @@ class NullSafeTransformer extends Plugin * @param NullsafePropertyFetch $fetch * @return PropertyFetch */ - public function enterPropertyFetch(NullsafePropertyFetch $fetch): PropertyFetch + public function enterPropertyFetch(NullsafePropertyFetch $fetch) { - return new PropertyFetch(new Coalesce($fetch->var, new StaticPropertyFetch(new FullyQualified(NullSafe::class), 'singleton')), $fetch->name); + $phabelReturn = new PropertyFetch(new Coalesce($fetch->var, new StaticPropertyFetch(new FullyQualified(NullSafe::class), 'singleton')), $fetch->name); + if (!$phabelReturn instanceof PropertyFetch) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type PropertyFetch, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Method call. * * @param NullsafeMethodCall $fetch * @return MethodCall */ - public function enterMethodCall(NullsafeMethodCall $fetch): MethodCall + public function enterMethodCall(NullsafeMethodCall $fetch) { - return new MethodCall(new Coalesce($fetch->var, new StaticPropertyFetch(new FullyQualified(NullSafe::class), 'singleton')), $fetch->name, $fetch->args); + $phabelReturn = new MethodCall(new Coalesce($fetch->var, new StaticPropertyFetch(new FullyQualified(NullSafe::class), 'singleton')), $fetch->name, $fetch->args); + if (!$phabelReturn instanceof MethodCall) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type MethodCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public static function previous(array $config): array + public static function previous(array $config) { - return [NestedExpressionFixer::class => [New_::class => ['class' => [NullsafePropertyFetch::class => true, NullsafeMethodCall::class => true]]]]; + $phabelReturn = [NestedExpressionFixer::class => [New_::class => ['class' => [NullsafePropertyFetch::class => \true, NullsafeMethodCall::class => \true]]]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php80/Polyfill.php b/src/Target/Php80/Polyfill.php index d581088cf..2ff6e1335 100644 --- a/src/Target/Php80/Polyfill.php +++ b/src/Target/Php80/Polyfill.php @@ -5,11 +5,9 @@ use Phabel\Plugin; use Phabel\Target\Polyfill as TargetPolyfill; use Phabel\Tools; - if (!\defined('CAL_EASTER_DEFAULT')) { \define('CAL_EASTER_DEFAULT', 0); } - /** * @author Daniil Gentili * @license MIT @@ -17,340 +15,1650 @@ class Polyfill extends Plugin { // Todo: nullability of a bunch of mb_ functions - - public static function easter_date(?int $year = null, int $mode = CAL_EASTER_DEFAULT): int + public static function easter_date($year = null, $mode = \CAL_EASTER_DEFAULT) { - $year ??= (int) \date('Y'); - return easter_date($year, $mode); + if (!\is_null($year)) { + if (!\is_int($year)) { + if (!(\is_bool($year) || \is_numeric($year))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($year) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($year) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $year = (int) $year; + } + } + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($mode) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $mode = (int) $mode; + } + $year = isset($year) ? $year : (int) \date('Y'); + $phabelReturn = \easter_date($year, $mode); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - - public static function easter_days(?int $year = null, int $mode = CAL_EASTER_DEFAULT): int + public static function easter_days($year = null, $mode = \CAL_EASTER_DEFAULT) { - $year ??= (int) \date('Y'); - return easter_days($year, $mode); + if (!\is_null($year)) { + if (!\is_int($year)) { + if (!(\is_bool($year) || \is_numeric($year))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($year) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($year) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $year = (int) $year; + } + } + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($mode) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $mode = (int) $mode; + } + $year = isset($year) ? $year : (int) \date('Y'); + $phabelReturn = \easter_days($year, $mode); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - - public static function unixtojd(?int $timestamp = null): int|bool + public static function unixtojd($timestamp = null) { - $timestamp ??= \time(); - return unixtojd($timestamp); + if (!\is_null($timestamp)) { + if (!\is_int($timestamp)) { + if (!(\is_bool($timestamp) || \is_numeric($timestamp))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($timestamp) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timestamp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $timestamp = (int) $timestamp; + } + } + $timestamp = isset($timestamp) ? $timestamp : \time(); + $phabelReturn = \unixtojd($timestamp); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function date_sunrise( - int $timestamp, - int $returnFormat = SUNFUNCS_RET_STRING, - ?float $latitude = null, - ?float $longitude = null, - ?float $zenith = null, - ?float $utcOffset = null - ): string|int|float|bool { - $latitude ??= Tools::ini_get('date.default_latitude'); - $longitude ??= Tools::ini_get('date.default_longitude'); - $zenith ??= Tools::ini_get('date.sunrise_zenith'); - $utcOffset ??= 0; - return \date_sunrise($timestamp, $returnFormat, $latitude, $longitude, $zenith, $utcOffset); - } - public static function date_sunset( - int $timestamp, - int $returnFormat = SUNFUNCS_RET_STRING, - ?float $latitude = null, - ?float $longitude = null, - ?float $zenith = null, - ?float $utcOffset = null - ): string|int|float|bool { - $latitude ??= Tools::ini_get('date.default_latitude'); - $longitude ??= Tools::ini_get('date.default_longitude'); - $zenith ??= Tools::ini_get('date.sunset_zenith'); - $utcOffset ??= 0; - return \date_sunset($timestamp, $returnFormat, $latitude, $longitude, $zenith, $utcOffset); + public static function date_sunrise($timestamp, $returnFormat = \SUNFUNCS_RET_STRING, $latitude = null, $longitude = null, $zenith = null, $utcOffset = null) + { + if (!\is_int($timestamp)) { + if (!(\is_bool($timestamp) || \is_numeric($timestamp))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($timestamp) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timestamp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $timestamp = (int) $timestamp; + } + if (!\is_int($returnFormat)) { + if (!(\is_bool($returnFormat) || \is_numeric($returnFormat))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($returnFormat) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($returnFormat) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $returnFormat = (int) $returnFormat; + } + if (!\is_null($latitude)) { + if (!\is_float($latitude)) { + if (!(\is_bool($latitude) || \is_numeric($latitude))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($latitude) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($latitude) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $latitude = (float) $latitude; + } + } + if (!\is_null($longitude)) { + if (!\is_float($longitude)) { + if (!(\is_bool($longitude) || \is_numeric($longitude))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($longitude) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($longitude) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $longitude = (float) $longitude; + } + } + if (!\is_null($zenith)) { + if (!\is_float($zenith)) { + if (!(\is_bool($zenith) || \is_numeric($zenith))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($zenith) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($zenith) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $zenith = (float) $zenith; + } + } + if (!\is_null($utcOffset)) { + if (!\is_float($utcOffset)) { + if (!(\is_bool($utcOffset) || \is_numeric($utcOffset))) { + throw new \TypeError(__METHOD__ . '(): Argument #6 ($utcOffset) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($utcOffset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $utcOffset = (float) $utcOffset; + } + } + $latitude = isset($latitude) ? $latitude : Tools::ini_get('date.default_latitude'); + $longitude = isset($longitude) ? $longitude : Tools::ini_get('date.default_longitude'); + $zenith = isset($zenith) ? $zenith : Tools::ini_get('date.sunrise_zenith'); + $utcOffset = isset($utcOffset) ? $utcOffset : 0; + $phabelReturn = \date_sunrise($timestamp, $returnFormat, $latitude, $longitude, $zenith, $utcOffset); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|int|float|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } else { + $phabelReturn = (float) $phabelReturn; + } + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function date(string $format, ?int $timestamp = null): string + public static function date_sunset($timestamp, $returnFormat = \SUNFUNCS_RET_STRING, $latitude = null, $longitude = null, $zenith = null, $utcOffset = null) { - return \date($format, $timestamp ?? \time()); + if (!\is_int($timestamp)) { + if (!(\is_bool($timestamp) || \is_numeric($timestamp))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($timestamp) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timestamp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $timestamp = (int) $timestamp; + } + if (!\is_int($returnFormat)) { + if (!(\is_bool($returnFormat) || \is_numeric($returnFormat))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($returnFormat) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($returnFormat) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $returnFormat = (int) $returnFormat; + } + if (!\is_null($latitude)) { + if (!\is_float($latitude)) { + if (!(\is_bool($latitude) || \is_numeric($latitude))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($latitude) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($latitude) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $latitude = (float) $latitude; + } + } + if (!\is_null($longitude)) { + if (!\is_float($longitude)) { + if (!(\is_bool($longitude) || \is_numeric($longitude))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($longitude) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($longitude) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $longitude = (float) $longitude; + } + } + if (!\is_null($zenith)) { + if (!\is_float($zenith)) { + if (!(\is_bool($zenith) || \is_numeric($zenith))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($zenith) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($zenith) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $zenith = (float) $zenith; + } + } + if (!\is_null($utcOffset)) { + if (!\is_float($utcOffset)) { + if (!(\is_bool($utcOffset) || \is_numeric($utcOffset))) { + throw new \TypeError(__METHOD__ . '(): Argument #6 ($utcOffset) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($utcOffset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $utcOffset = (float) $utcOffset; + } + } + $latitude = isset($latitude) ? $latitude : Tools::ini_get('date.default_latitude'); + $longitude = isset($longitude) ? $longitude : Tools::ini_get('date.default_longitude'); + $zenith = isset($zenith) ? $zenith : Tools::ini_get('date.sunset_zenith'); + $utcOffset = isset($utcOffset) ? $utcOffset : 0; + $phabelReturn = \date_sunset($timestamp, $returnFormat, $latitude, $longitude, $zenith, $utcOffset); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|int|float|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } else { + $phabelReturn = (float) $phabelReturn; + } + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function getdate(?int $timestamp = null): array + public static function date($format, $timestamp = null) { - return \getdate($timestamp ?? \time()); + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $format = (string) $format; + } + if (!\is_null($timestamp)) { + if (!\is_int($timestamp)) { + if (!(\is_bool($timestamp) || \is_numeric($timestamp))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($timestamp) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timestamp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $timestamp = (int) $timestamp; + } + } + $phabelReturn = \date($format, isset($timestamp) ? $timestamp : \time()); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - - public static function gmdate(string $format, ?int $timestamp = null): string + public static function getdate($timestamp = null) { - return \gmdate($format, $timestamp ?? \time()); + if (!\is_null($timestamp)) { + if (!\is_int($timestamp)) { + if (!(\is_bool($timestamp) || \is_numeric($timestamp))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($timestamp) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timestamp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $timestamp = (int) $timestamp; + } + } + $phabelReturn = \getdate(isset($timestamp) ? $timestamp : \time()); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public static function gmstrftime(string $format, ?int $timestamp = null): string|bool + public static function gmdate($format, $timestamp = null) { - return \gmstrftime($format, $timestamp ?? \time()); + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $format = (string) $format; + } + if (!\is_null($timestamp)) { + if (!\is_int($timestamp)) { + if (!(\is_bool($timestamp) || \is_numeric($timestamp))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($timestamp) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timestamp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $timestamp = (int) $timestamp; + } + } + $phabelReturn = \gmdate($format, isset($timestamp) ? $timestamp : \time()); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - - public static function idate(string $format, ?int $timestamp = null): int|bool + public static function gmstrftime($format, $timestamp = null) { - return \idate($format, $timestamp ?? \time()); + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $format = (string) $format; + } + if (!\is_null($timestamp)) { + if (!\is_int($timestamp)) { + if (!(\is_bool($timestamp) || \is_numeric($timestamp))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($timestamp) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timestamp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $timestamp = (int) $timestamp; + } + } + $phabelReturn = \gmstrftime($format, isset($timestamp) ? $timestamp : \time()); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function localtime(?int $timestamp = null, bool $associative = false): array + public static function idate($format, $timestamp = null) { - return \localtime($timestamp ?? \time(), $associative); + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $format = (string) $format; + } + if (!\is_null($timestamp)) { + if (!\is_int($timestamp)) { + if (!(\is_bool($timestamp) || \is_numeric($timestamp))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($timestamp) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timestamp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $timestamp = (int) $timestamp; + } + } + $phabelReturn = \idate($format, isset($timestamp) ? $timestamp : \time()); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function strftime(string $format, ?int $timestamp = null): string|bool + public static function localtime($timestamp = null, $associative = \false) { - return \strftime($format, $timestamp ?? \time()); + if (!\is_null($timestamp)) { + if (!\is_int($timestamp)) { + if (!(\is_bool($timestamp) || \is_numeric($timestamp))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($timestamp) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timestamp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $timestamp = (int) $timestamp; + } + } + if (!\is_bool($associative)) { + if (!(\is_bool($associative) || \is_numeric($associative) || \is_string($associative))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($associative) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($associative) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $associative = (bool) $associative; + } + $phabelReturn = \localtime(isset($timestamp) ? $timestamp : \time(), $associative); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public static function strtotime(string $datetime, ?int $baseTimestamp = null): int|bool + public static function strftime($format, $timestamp = null) { - return \strtotime($datetime, $baseTimestamp ?? \time()); + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $format = (string) $format; + } + if (!\is_null($timestamp)) { + if (!\is_int($timestamp)) { + if (!(\is_bool($timestamp) || \is_numeric($timestamp))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($timestamp) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timestamp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $timestamp = (int) $timestamp; + } + } + $phabelReturn = \strftime($format, isset($timestamp) ? $timestamp : \time()); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function error_reporting(?int $error_level = null): int + public static function strtotime($datetime, $baseTimestamp = null) { - return $error_level === null ? \error_reporting() : \error_reporting($error_level); + if (!\is_string($datetime)) { + if (!(\is_string($datetime) || \is_object($datetime) && \method_exists($datetime, '__toString') || (\is_bool($datetime) || \is_numeric($datetime)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($datetime) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($datetime) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $datetime = (string) $datetime; + } + if (!\is_null($baseTimestamp)) { + if (!\is_int($baseTimestamp)) { + if (!(\is_bool($baseTimestamp) || \is_numeric($baseTimestamp))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($baseTimestamp) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($baseTimestamp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $baseTimestamp = (int) $baseTimestamp; + } + } + $phabelReturn = \strtotime($datetime, isset($baseTimestamp) ? $baseTimestamp : \time()); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function hash_update_file($context, string $filename, $stream_context = null): bool + public static function error_reporting($error_level = null) { - return $stream_context ? \hash_update_file($context, $filename, $stream_context) : \hash_update_file($context, $filename); + if (!\is_null($error_level)) { + if (!\is_int($error_level)) { + if (!(\is_bool($error_level) || \is_numeric($error_level))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($error_level) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($error_level) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $error_level = (int) $error_level; + } + } + $phabelReturn = $error_level === null ? \error_reporting() : \error_reporting($error_level); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - - public static function iconv_mime_decode_headers(string $headers, int $mode = 0, ?string $encoding = null): array|false + public static function hash_update_file($context, $filename, $stream_context = null) { - return \iconv_mime_decode_headers($headers, $mode, $encoding ?? \iconv_get_encoding('internal_encoding')); + if (!\is_string($filename)) { + if (!(\is_string($filename) || \is_object($filename) && \method_exists($filename, '__toString') || (\is_bool($filename) || \is_numeric($filename)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($filename) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($filename) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $filename = (string) $filename; + } + $phabelReturn = $stream_context ? \hash_update_file($context, $filename, $stream_context) : \hash_update_file($context, $filename); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - - public static function iconv_mime_decode(string $string, int $mode = 0, ?string $encoding = null): string|bool + public static function iconv_mime_decode_headers($headers, $mode = 0, $encoding = null) { - return \iconv_mime_decode($string, $mode, $encoding ?? \iconv_get_encoding('internal_encoding')); + if (!\is_string($headers)) { + if (!(\is_string($headers) || \is_object($headers) && \method_exists($headers, '__toString') || (\is_bool($headers) || \is_numeric($headers)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($headers) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($headers) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $headers = (string) $headers; + } + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($mode) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $mode = (int) $mode; + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + $phabelReturn = \iconv_mime_decode_headers($headers, $mode, isset($encoding) ? $encoding : \iconv_get_encoding('internal_encoding')); + if (!(\is_array($phabelReturn) || $phabelReturn instanceof \Phabel\Target\Php80\false)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public static function iconv_strlen(string $string, ?string $encoding = null): int|bool + public static function iconv_mime_decode($string, $mode = 0, $encoding = null) { - return \iconv_strlen($string, $encoding ?? \iconv_get_encoding('internal_encoding')); + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($mode) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $mode = (int) $mode; + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + $phabelReturn = \iconv_mime_decode($string, $mode, isset($encoding) ? $encoding : \iconv_get_encoding('internal_encoding')); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function iconv_strpos( - string $haystack, - string $needle, - int $offset = 0, - ?string $encoding = null - ): int|bool { - return \iconv_strpos($haystack, $needle, $offset, $encoding ?? \iconv_get_encoding('internal_encoding')); + public static function iconv_strlen($string, $encoding = null) + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + $phabelReturn = \iconv_strlen($string, isset($encoding) ? $encoding : \iconv_get_encoding('internal_encoding')); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function iconv_strrpos(string $haystack, string $needle, ?string $encoding = null): int|bool + public static function iconv_strpos($haystack, $needle, $offset = 0, $encoding = null) { - return \iconv_strrpos($haystack, $needle, $encoding ?? \iconv_get_encoding('internal_encoding')); + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $haystack = (string) $haystack; + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $needle = (string) $needle; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + $phabelReturn = \iconv_strpos($haystack, $needle, $offset, isset($encoding) ? $encoding : \iconv_get_encoding('internal_encoding')); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function iconv_substr( - string $string, - int $offset, - ?int $length = null, - ?string $encoding = null - ): string|bool { - return \iconv_substr($string, $offset, $length, $encoding ?? \iconv_get_encoding('internal_encoding')); + public static function iconv_strrpos($haystack, $needle, $encoding = null) + { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $haystack = (string) $haystack; + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $needle = (string) $needle; + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + $phabelReturn = \iconv_strrpos($haystack, $needle, isset($encoding) ? $encoding : \iconv_get_encoding('internal_encoding')); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function get_resources(?string $type = null): array + public static function iconv_substr($string, $offset, $length = null, $encoding = null) { - return $type === null ? \get_resources() : \get_resources($type); + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $length = (int) $length; + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + $phabelReturn = \iconv_substr($string, $offset, $length, isset($encoding) ? $encoding : \iconv_get_encoding('internal_encoding')); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function mhash(int $algo, string $data, ?string $key = null): string|bool + public static function get_resources($type = null) { - return $key === null ? \mhash($algo, $data) : \mhash($algo, $data); + if (!\is_null($type)) { + if (!\is_string($type)) { + if (!(\is_string($type) || \is_object($type) && \method_exists($type, '__toString') || (\is_bool($type) || \is_numeric($type)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($type) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $type = (string) $type; + } + } + $phabelReturn = $type === null ? \get_resources() : \get_resources($type); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - public static function ignore_user_abort(?bool $enable = null): int + public static function mhash($algo, $data, $key = null) { - return $enable === null ? \ignore_user_abort() : \ignore_user_abort($enable); + if (!\is_int($algo)) { + if (!(\is_bool($algo) || \is_numeric($algo))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($algo) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($algo) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $algo = (int) $algo; + } + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $data = (string) $data; + } + if (!\is_null($key)) { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($key) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $key = (string) $key; + } + } + $phabelReturn = $key === null ? \mhash($algo, $data) : \mhash($algo, $data); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function fsockopen( - string $hostname, - int $port = -1, - int &$error_code = null, - string &$error_message = null, - ?float $timeout = null - ) { + public static function ignore_user_abort($enable = null) + { + if (!\is_null($enable)) { + if (!\is_bool($enable)) { + if (!(\is_bool($enable) || \is_numeric($enable) || \is_string($enable))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($enable) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($enable) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $enable = (bool) $enable; + } + } + $phabelReturn = $enable === null ? \ignore_user_abort() : \ignore_user_abort($enable); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; + } + public static function fsockopen($hostname, $port = -1, &$error_code = null, &$error_message = null, $timeout = null) + { + if (!\is_string($hostname)) { + if (!(\is_string($hostname) || \is_object($hostname) && \method_exists($hostname, '__toString') || (\is_bool($hostname) || \is_numeric($hostname)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($hostname) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($hostname) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $hostname = (string) $hostname; + } + if (!\is_int($port)) { + if (!(\is_bool($port) || \is_numeric($port))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($port) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($port) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $port = (int) $port; + } + if (!\is_null($error_code)) { + if (!\is_int($error_code)) { + if (!(\is_bool($error_code) || \is_numeric($error_code))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($error_code) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($error_code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $error_code = (int) $error_code; + } + } + if (!\is_null($error_message)) { + if (!\is_string($error_message)) { + if (!(\is_string($error_message) || \is_object($error_message) && \method_exists($error_message, '__toString') || (\is_bool($error_message) || \is_numeric($error_message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($error_message) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($error_message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $error_message = (string) $error_message; + } + } + if (!\is_null($timeout)) { + if (!\is_float($timeout)) { + if (!(\is_bool($timeout) || \is_numeric($timeout))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($timeout) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeout) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $timeout = (float) $timeout; + } + } return $timeout === null ? \fsockopen($hostname, $port, $error_code, $error_message) : \fsockopen($hostname, $port, $error_code, $error_message); } - - public static function ob_implicit_flush(bool $flag = true): void + public static function ob_implicit_flush($flag = \true) { + if (!\is_bool($flag)) { + if (!(\is_bool($flag) || \is_numeric($flag) || \is_string($flag))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($flag) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($flag) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $flag = (bool) $flag; + } \ob_implicit_flush((int) $flag); } - - public static function password_hash(string $password, string|int|null $algo, array $options = []): string + public static function password_hash($password, $algo, array $options = []) { - return \password_hash($password, $algo ?? PASSWORD_DEFAULT, $options); + if (!\is_string($password)) { + if (!(\is_string($password) || \is_object($password) && \method_exists($password, '__toString') || (\is_bool($password) || \is_numeric($password)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($password) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($password) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $password = (string) $password; + } + if (!\is_null($algo)) { + if (!\is_int($algo)) { + if (!(\is_bool($algo) || \is_numeric($algo))) { + if (!\is_string($algo)) { + if (!(\is_string($algo) || \is_object($algo) && \method_exists($algo, '__toString') || (\is_bool($algo) || \is_numeric($algo)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($algo) must be of type string|int|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($algo) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $algo = (string) $algo; + } + } else { + $algo = (int) $algo; + } + } + } + $phabelReturn = \password_hash($password, isset($algo) ? $algo : \PASSWORD_DEFAULT, $options); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - - public static function pcntl_async_signals(?bool $enable = null): bool + public static function pcntl_async_signals($enable = null) { - return $enable === null ? \pcntl_async_signals() : \pcntl_async_signals($enable); + if (!\is_null($enable)) { + if (!\is_bool($enable)) { + if (!(\is_bool($enable) || \is_numeric($enable) || \is_string($enable))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($enable) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($enable) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $enable = (bool) $enable; + } + } + $phabelReturn = $enable === null ? \pcntl_async_signals() : \pcntl_async_signals($enable); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - - public static function pcntl_getpriority(?int $process_id = null, int $mode = PRIO_PROCESS): int|bool + public static function pcntl_getpriority($process_id = null, $mode = \PRIO_PROCESS) { - return \pcntl_getpriority($process_id ?? \getmypid(), $mode); + if (!\is_null($process_id)) { + if (!\is_int($process_id)) { + if (!(\is_bool($process_id) || \is_numeric($process_id))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($process_id) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($process_id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $process_id = (int) $process_id; + } + } + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($mode) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $mode = (int) $mode; + } + $phabelReturn = \pcntl_getpriority(isset($process_id) ? $process_id : \getmypid(), $mode); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function pcntl_setpriority(int $priority, ?int $process_id = null, int $mode = PRIO_PROCESS): bool + public static function pcntl_setpriority($priority, $process_id = null, $mode = \PRIO_PROCESS) { - return \pcntl_setpriority($priority, $process_id ?? \getmypid(), $mode); + if (!\is_int($priority)) { + if (!(\is_bool($priority) || \is_numeric($priority))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($priority) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($priority) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $priority = (int) $priority; + } + if (!\is_null($process_id)) { + if (!\is_int($process_id)) { + if (!(\is_bool($process_id) || \is_numeric($process_id))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($process_id) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($process_id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $process_id = (int) $process_id; + } + } + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($mode) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $mode = (int) $mode; + } + $phabelReturn = \pcntl_setpriority($priority, isset($process_id) ? $process_id : \getmypid(), $mode); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - - public static function readline_info(?string $var_name = null, int|string|bool|null $value = null) + public static function readline_info($var_name = null, $value = null) { + if (!\is_null($var_name)) { + if (!\is_string($var_name)) { + if (!(\is_string($var_name) || \is_object($var_name) && \method_exists($var_name, '__toString') || (\is_bool($var_name) || \is_numeric($var_name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($var_name) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($var_name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $var_name = (string) $var_name; + } + } + if (!(\is_null($value) || \is_null($value))) { + if (!\is_bool($value)) { + if (!(\is_bool($value) || \is_numeric($value) || \is_string($value))) { + if (!\is_string($value)) { + if (!(\is_string($value) || \is_object($value) && \method_exists($value, '__toString') || (\is_bool($value) || \is_numeric($value)))) { + if (!\is_int($value)) { + if (!(\is_bool($value) || \is_numeric($value))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($value) must be of type ?int|string|bool|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($value) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $value = (int) $value; + } + } else { + $value = (string) $value; + } + } + } else { + $value = (bool) $value; + } + } + } return $var_name === null && $value === null ? \readline_info() : \readline_info($var_name, $value); } - - public static function readline_read_history(?string $filename = null): bool + public static function readline_read_history($filename = null) { - return $filename === null ? \readline_read_history() : \readline_read_history($filename); + if (!\is_null($filename)) { + if (!\is_string($filename)) { + if (!(\is_string($filename) || \is_object($filename) && \method_exists($filename, '__toString') || (\is_bool($filename) || \is_numeric($filename)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($filename) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($filename) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $filename = (string) $filename; + } + } + $phabelReturn = $filename === null ? \readline_read_history() : \readline_read_history($filename); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - - public static function readline_write_history(?string $filename = null): bool + public static function readline_write_history($filename = null) { - return $filename === null ? \readline_read_history() : \readline_write_history($filename); + if (!\is_null($filename)) { + if (!\is_string($filename)) { + if (!(\is_string($filename) || \is_object($filename) && \method_exists($filename, '__toString') || (\is_bool($filename) || \is_numeric($filename)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($filename) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($filename) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $filename = (string) $filename; + } + } + $phabelReturn = $filename === null ? \readline_read_history() : \readline_write_history($filename); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - - public static function session_cache_expire(?int $value = null): int|bool + public static function session_cache_expire($value = null) { - return $value === null ? \session_cache_expire() : \session_cache_expire($value); + if (!\is_null($value)) { + if (!\is_int($value)) { + if (!(\is_bool($value) || \is_numeric($value))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($value) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($value) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $value = (int) $value; + } + } + $phabelReturn = $value === null ? \session_cache_expire() : \session_cache_expire($value); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function session_cache_limiter(?string $value = null): string|bool + public static function session_cache_limiter($value = null) { - return $value === null ? \session_cache_limiter() : \session_cache_limiter($value); + if (!\is_null($value)) { + if (!\is_string($value)) { + if (!(\is_string($value) || \is_object($value) && \method_exists($value, '__toString') || (\is_bool($value) || \is_numeric($value)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($value) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($value) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $value = (string) $value; + } + } + $phabelReturn = $value === null ? \session_cache_limiter() : \session_cache_limiter($value); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function session_id(?string $id = null): string|bool + public static function session_id($id = null) { - return $id === null ? \session_id() : \session_id($id); + if (!\is_null($id)) { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $id = (string) $id; + } + } + $phabelReturn = $id === null ? \session_id() : \session_id($id); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function session_module_name(?string $module = null): string|bool + public static function session_module_name($module = null) { - return $module === null ? \session_module_name() : \session_module_name($module); + if (!\is_null($module)) { + if (!\is_string($module)) { + if (!(\is_string($module) || \is_object($module) && \method_exists($module, '__toString') || (\is_bool($module) || \is_numeric($module)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($module) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($module) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $module = (string) $module; + } + } + $phabelReturn = $module === null ? \session_module_name() : \session_module_name($module); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function session_name(?string $name = null): string|bool + public static function session_name($name = null) { - return $name === null ? \session_name() : \session_name($name); + if (!\is_null($name)) { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $name = (string) $name; + } + } + $phabelReturn = $name === null ? \session_name() : \session_name($name); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function session_save_path(?string $path = null): string|bool + public static function session_save_path($path = null) { - return $path === null ? \session_save_path() : \session_save_path($path); + if (!\is_null($path)) { + if (!\is_string($path)) { + if (!(\is_string($path) || \is_object($path) && \method_exists($path, '__toString') || (\is_bool($path) || \is_numeric($path)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($path) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($path) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $path = (string) $path; + } + } + $phabelReturn = $path === null ? \session_save_path() : \session_save_path($path); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; } - - public static function session_set_cookie_params( - int|array $lifetime_or_options, - ?string $path = null, - ?string $domain = null, - ?bool $secure = null, - ?bool $httponly = null - ): bool { - return \is_array($lifetime_or_options) - ? \session_set_cookie_params($lifetime_or_options) - : \session_set_cookie_params(\array_filter(['lifetime' => $lifetime_or_options, 'path' => $path, 'domain' => $domain, 'secure' => $secure, 'httponly' => $httponly])); + public static function session_set_cookie_params($lifetime_or_options, $path = null, $domain = null, $secure = null, $httponly = null) + { + if (!\is_array($lifetime_or_options)) { + if (!\is_int($lifetime_or_options)) { + if (!(\is_bool($lifetime_or_options) || \is_numeric($lifetime_or_options))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($lifetime_or_options) must be of type int|array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($lifetime_or_options) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $lifetime_or_options = (int) $lifetime_or_options; + } + } + if (!\is_null($path)) { + if (!\is_string($path)) { + if (!(\is_string($path) || \is_object($path) && \method_exists($path, '__toString') || (\is_bool($path) || \is_numeric($path)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($path) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($path) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $path = (string) $path; + } + } + if (!\is_null($domain)) { + if (!\is_string($domain)) { + if (!(\is_string($domain) || \is_object($domain) && \method_exists($domain, '__toString') || (\is_bool($domain) || \is_numeric($domain)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($domain) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($domain) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $domain = (string) $domain; + } + } + if (!\is_null($secure)) { + if (!\is_bool($secure)) { + if (!(\is_bool($secure) || \is_numeric($secure) || \is_string($secure))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($secure) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($secure) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $secure = (bool) $secure; + } + } + if (!\is_null($httponly)) { + if (!\is_bool($httponly)) { + if (!(\is_bool($httponly) || \is_numeric($httponly) || \is_string($httponly))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($httponly) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($httponly) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $httponly = (bool) $httponly; + } + } + $phabelReturn = \is_array($lifetime_or_options) ? \session_set_cookie_params($lifetime_or_options) : \session_set_cookie_params(\array_filter(['lifetime' => $lifetime_or_options, 'path' => $path, 'domain' => $domain, 'secure' => $secure, 'httponly' => $httponly])); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - - public static function spl_autoload_extensions(?string $file_extensions = null): string + public static function spl_autoload_extensions($file_extensions = null) { - return $file_extensions === null ? \spl_autoload_extensions() : \spl_autoload_extensions($file_extensions); + if (!\is_null($file_extensions)) { + if (!\is_string($file_extensions)) { + if (!(\is_string($file_extensions) || \is_object($file_extensions) && \method_exists($file_extensions, '__toString') || (\is_bool($file_extensions) || \is_numeric($file_extensions)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($file_extensions) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file_extensions) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $file_extensions = (string) $file_extensions; + } + } + $phabelReturn = $file_extensions === null ? \spl_autoload_extensions() : \spl_autoload_extensions($file_extensions); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - - public static function spl_autoload_register(?callable $callback = null, bool $throw = true, bool $prepend = false): bool + public static function spl_autoload_register($callback = null, $throw = \true, $prepend = \false) { - return \spl_autoload_register($callback ?? 'spl_autoload', $throw, $prepend); + if (!(\is_callable($callback) || \is_null($callback))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($callback) must be of type ?callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($callback) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_bool($throw)) { + if (!(\is_bool($throw) || \is_numeric($throw) || \is_string($throw))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($throw) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($throw) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $throw = (bool) $throw; + } + if (!\is_bool($prepend)) { + if (!(\is_bool($prepend) || \is_numeric($prepend) || \is_string($prepend))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($prepend) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($prepend) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $prepend = (bool) $prepend; + } + $phabelReturn = \spl_autoload_register(isset($callback) ? $callback : 'spl_autoload', $throw, $prepend); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - - public static function spl_autoload(string $class, ?string $file_extensions = null): void + public static function spl_autoload($class, $file_extensions = null) { + if (!\is_string($class)) { + if (!(\is_string($class) || \is_object($class) && \method_exists($class, '__toString') || (\is_bool($class) || \is_numeric($class)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($class) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($class) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $class = (string) $class; + } + if (!\is_null($file_extensions)) { + if (!\is_string($file_extensions)) { + if (!(\is_string($file_extensions) || \is_object($file_extensions) && \method_exists($file_extensions, '__toString') || (\is_bool($file_extensions) || \is_numeric($file_extensions)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($file_extensions) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file_extensions) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $file_extensions = (string) $file_extensions; + } + } $file_extensions === null ? \spl_autoload($class) : \spl_autoload($class, $file_extensions); } - - public static function html_entity_decode(string $string, int $flags = ENT_COMPAT, ?string $encoding = null): string + public static function html_entity_decode($string, $flags = \ENT_COMPAT, $encoding = null) { - return \html_entity_decode($string, $flags, $encoding ?? Tools::ini_get('default_charset')); + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_int($flags)) { + if (!(\is_bool($flags) || \is_numeric($flags))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($flags) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($flags) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $flags = (int) $flags; + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + $phabelReturn = \html_entity_decode($string, $flags, isset($encoding) ? $encoding : Tools::ini_get('default_charset')); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - - public static function htmlentities( - string $string, - int $flags = ENT_COMPAT, - ?string $encoding = null, - bool $double_encode = true - ): string { - return \htmlentities($string, $flags, $encoding ?? Tools::ini_get('default_charset'), $double_encode); + public static function htmlentities($string, $flags = \ENT_COMPAT, $encoding = null, $double_encode = \true) + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_int($flags)) { + if (!(\is_bool($flags) || \is_numeric($flags))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($flags) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($flags) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $flags = (int) $flags; + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $encoding = (string) $encoding; + } + } + if (!\is_bool($double_encode)) { + if (!(\is_bool($double_encode) || \is_numeric($double_encode) || \is_string($double_encode))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($double_encode) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($double_encode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $double_encode = (bool) $double_encode; + } + $phabelReturn = \htmlentities($string, $flags, isset($encoding) ? $encoding : Tools::ini_get('default_charset'), $double_encode); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - - public static function str_word_count(string $string, int $format = 0, ?string $characters = null): array|int + public static function str_word_count($string, $format = 0, $characters = null) { - return $format === null ? \str_word_count($string, $format) : \str_word_count($string, $format, $characters); + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_int($format)) { + if (!(\is_bool($format) || \is_numeric($format))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($format) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $format = (int) $format; + } + if (!\is_null($characters)) { + if (!\is_string($characters)) { + if (!(\is_string($characters) || \is_object($characters) && \method_exists($characters, '__toString') || (\is_bool($characters) || \is_numeric($characters)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($characters) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($characters) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $characters = (string) $characters; + } + } + $phabelReturn = $format === null ? \str_word_count($string, $format) : \str_word_count($string, $format, $characters); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; } - public static function strcspn( - string $string, - string $characters, - int $offset = 0, - ?int $length = null - ): int { - return $length === null ? \strcspn($string, $characters, $offset) : \strcspn($string, $characters, $offset, $length); + public static function strcspn($string, $characters, $offset = 0, $length = null) + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_string($characters)) { + if (!(\is_string($characters) || \is_object($characters) && \method_exists($characters, '__toString') || (\is_bool($characters) || \is_numeric($characters)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($characters) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($characters) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $characters = (string) $characters; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $length = (int) $length; + } + } + $phabelReturn = $length === null ? \strcspn($string, $characters, $offset) : \strcspn($string, $characters, $offset, $length); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - public static function strip_tags(string $string, array|string|null $allowed_tags = null): string + public static function strip_tags($string, $allowed_tags = null) { - return $allowed_tags === null ? \strip_tags($string) : \strip_tags($string, $allowed_tags); + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!(\is_null($allowed_tags) || \is_null($allowed_tags))) { + if (!\is_string($allowed_tags)) { + if (!(\is_string($allowed_tags) || \is_object($allowed_tags) && \method_exists($allowed_tags, '__toString') || (\is_bool($allowed_tags) || \is_numeric($allowed_tags)))) { + if (!\is_array($allowed_tags)) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($allowed_tags) must be of type ?array|string|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($allowed_tags) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $allowed_tags = (string) $allowed_tags; + } + } + } + $phabelReturn = $allowed_tags === null ? \strip_tags($string) : \strip_tags($string, $allowed_tags); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - - public static function strspn( - string $string, - string $characters, - int $offset = 0, - ?int $length = null - ): int { - return $length === null ? \strspn($string, $characters, $offset) : \strspn($string, $characters, $offset, $length); - } - public static function substr_compare( - string $haystack, - string $needle, - int $offset, - ?int $length = null, - bool $case_insensitive = false - ): int { - return \substr_compare($haystack, $needle, $offset, $length ?? \max(\strlen($needle), \strlen($haystack)-($offset < 0 ? \strlen($haystack)+$offset : $offset)), $case_insensitive); + public static function strspn($string, $characters, $offset = 0, $length = null) + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_string($characters)) { + if (!(\is_string($characters) || \is_object($characters) && \method_exists($characters, '__toString') || (\is_bool($characters) || \is_numeric($characters)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($characters) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($characters) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $characters = (string) $characters; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $length = (int) $length; + } + } + $phabelReturn = $length === null ? \strspn($string, $characters, $offset) : \strspn($string, $characters, $offset, $length); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - - public static function substr_count( - string $haystack, - string $needle, - int $offset = 0, - ?int $length = null - ): int { - return $length === null ? \substr_count($haystack, $needle, $offset) : \substr_count($haystack, $needle, $offset, $length); + public static function substr_compare($haystack, $needle, $offset, $length = null, $case_insensitive = \false) + { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $haystack = (string) $haystack; + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $needle = (string) $needle; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $length = (int) $length; + } + } + if (!\is_bool($case_insensitive)) { + if (!(\is_bool($case_insensitive) || \is_numeric($case_insensitive) || \is_string($case_insensitive))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($case_insensitive) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($case_insensitive) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $case_insensitive = (bool) $case_insensitive; + } + $phabelReturn = \substr_compare($haystack, $needle, $offset, isset($length) ? $length : \max(\strlen($needle), \strlen($haystack) - ($offset < 0 ? \strlen($haystack) + $offset : $offset)), $case_insensitive); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - - public static function substr_replace( - array|string $string, - array|string $replace, - array|int $offset, - array|int|null $length = null - ): string|array { - return $length === null ? \substr_replace($string, $replace, $offset) : \substr_replace($string, $replace, $offset, $length); + public static function substr_count($haystack, $needle, $offset = 0, $length = null) + { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $haystack = (string) $haystack; + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $needle = (string) $needle; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $length = (int) $length; + } + } + $phabelReturn = $length === null ? \substr_count($haystack, $needle, $offset) : \substr_count($haystack, $needle, $offset, $length); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - public static function substr(string $string, int $offset, ?int $length = null): string + public static function substr_replace($string, $replace, $offset, $length = null) { - return $length === null ? \substr($string, $offset) : \substr($string, $offset, $length); + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + if (!\is_array($string)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type array|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $string = (string) $string; + } + } + if (!\is_string($replace)) { + if (!(\is_string($replace) || \is_object($replace) && \method_exists($replace, '__toString') || (\is_bool($replace) || \is_numeric($replace)))) { + if (!\is_array($replace)) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($replace) must be of type array|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($replace) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $replace = (string) $replace; + } + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + if (!\is_array($offset)) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type array|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $offset = (int) $offset; + } + } + if (!(\is_null($length) || \is_null($length))) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + if (!\is_array($length)) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($length) must be of type ?array|int|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $length = (int) $length; + } + } + } + $phabelReturn = $length === null ? \substr_replace($string, $replace, $offset) : \substr_replace($string, $replace, $offset, $length); + if (!\is_array($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public static function substr($string, $offset, $length = null) + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $string = (string) $string; + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $offset = (int) $offset; + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $length = (int) $length; + } + } + $phabelReturn = $length === null ? \substr($string, $offset) : \substr($string, $offset, $length); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - /** * {@inheritDoc} */ - public static function withNext(array $config): array + public static function withNext(array $config) { - return [TargetPolyfill::class => [self::class => true]]; + $phabelReturn = [TargetPolyfill::class => [self::class => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php80/StaticReplacer.php b/src/Target/Php80/StaticReplacer.php index 58758c22c..44752f935 100644 --- a/src/Target/Php80/StaticReplacer.php +++ b/src/Target/Php80/StaticReplacer.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\Plugin\TypeHintReplacer; - /** * Replace static typehint. * @@ -13,12 +12,12 @@ */ class StaticReplacer extends Plugin { - public static function previous(array $config): array + public static function previous(array $config) { - return [ - TypeHintReplacer::class => [ - 'types' => ['static'] - ] - ]; + $phabelReturn = [TypeHintReplacer::class => ['types' => ['static']]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Php80/ThrowExprReplacer.php b/src/Target/Php80/ThrowExprReplacer.php index 5b807c011..d21ca535c 100644 --- a/src/Target/Php80/ThrowExprReplacer.php +++ b/src/Target/Php80/ThrowExprReplacer.php @@ -3,19 +3,22 @@ namespace Phabel\Target\Php80; use Phabel\Plugin; -use PhpParser\Node\Expr\StaticCall; -use PhpParser\Node\Expr\Throw_ as ExprThrow_; - +use Phabel\PhpParser\Node\Expr\StaticCall; +use Phabel\PhpParser\Node\Expr\Throw_ as ExprThrow_; /** * Polyfill throw expression. */ class ThrowExprReplacer extends Plugin { - public function enter(ExprThrow_ $throw): StaticCall + public function enter(ExprThrow_ $throw) { - return self::callPoly('throwMe', $throw->expr); + $phabelReturn = self::callPoly('throwMe', $throw->expr); + if (!$phabelReturn instanceof StaticCall) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type StaticCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - public static function throwMe(\Throwable $expr): void + public static function throwMe(\Throwable $expr) { throw $expr; } diff --git a/src/Target/Php80/UnionTypeStripper.php b/src/Target/Php80/UnionTypeStripper.php index 09b1aa96a..1391bdd9f 100644 --- a/src/Target/Php80/UnionTypeStripper.php +++ b/src/Target/Php80/UnionTypeStripper.php @@ -4,7 +4,6 @@ use Phabel\Plugin; use Phabel\Plugin\TypeHintReplacer; - /** * Strip union types, polyfilling type checks. */ @@ -13,12 +12,12 @@ class UnionTypeStripper extends Plugin /** * {@inheritDoc} */ - public static function previous(array $config): array + public static function previous(array $config) { - return [ - TypeHintReplacer::class => [ - 'union' => true - ] - ]; + $phabelReturn = [TypeHintReplacer::class => ['union' => \true]]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Target/Polyfill.php b/src/Target/Polyfill.php index 4bf71802a..5c875b927 100644 --- a/src/Target/Polyfill.php +++ b/src/Target/Polyfill.php @@ -2,11 +2,7 @@ namespace Phabel\Target; -use Phabel\Context; use Phabel\Plugin; -use PhpParser\Node\Expr\FuncCall; -use PhpParser\Node\Expr\MethodCall; - /** * @author Daniil Gentili * @license MIT diff --git a/src/Tasks/Init.php b/src/Tasks/Init.php index d27074c43..7be23eb6e 100644 --- a/src/Tasks/Init.php +++ b/src/Tasks/Init.php @@ -2,12 +2,11 @@ namespace Phabel\Tasks; -use Amp\Parallel\Worker\Environment; -use Amp\Parallel\Worker\Task; +use Phabel\Amp\Parallel\Worker\Environment; +use Phabel\Amp\Parallel\Worker\Task; use Phabel\Exception; use Phabel\PluginGraph\ResolvedGraph; use Phabel\Traverser; - class Init implements Task { public function __construct(private ResolvedGraph $graph) @@ -18,18 +17,49 @@ public function run(Environment $environment) if (\function_exists("cli_set_process_title")) { try { @\cli_set_process_title("Phabel - PHP transpiler worker"); - } catch (\Throwable $e) { + } catch (\Exception $e) { + } catch (\Error $e) { } } - \set_error_handler( - function (int $errno = 0, string $errstr = '', string $errfile = '', int $errline = -1): bool { - // If error is suppressed with @, don't throw an exception - if (\error_reporting() === 0) { - return false; + \set_error_handler(function ($errno = 0, $errstr = '', $errfile = '', $errline = -1) { + if (!\is_int($errno)) { + if (!(\is_bool($errno) || \is_numeric($errno))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($errno) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($errno) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $errno = (int) $errno; + } + if (!\is_string($errstr)) { + if (!(\is_string($errstr) || \is_object($errstr) && \method_exists($errstr, '__toString') || (\is_bool($errstr) || \is_numeric($errstr)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($errstr) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($errstr) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $errstr = (string) $errstr; + } + if (!\is_string($errfile)) { + if (!(\is_string($errfile) || \is_object($errfile) && \method_exists($errfile, '__toString') || (\is_bool($errfile) || \is_numeric($errfile)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($errfile) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($errfile) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $errfile = (string) $errfile; + } + if (!\is_int($errline)) { + if (!(\is_bool($errline) || \is_numeric($errline))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($errline) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($errline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $errline = (int) $errline; + } + // If error is suppressed with @, don't throw an exception + if (\error_reporting() === 0) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; } - throw new Exception($errstr, $errno, null, $errfile, $errline); + return $phabelReturn; } - ); + throw new Exception($errstr, $errno, null, $errfile, $errline); + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + }); $environment->set(Traverser::class, (new Traverser())->setGraph($this->graph)); } } diff --git a/src/Tasks/Run.php b/src/Tasks/Run.php index 4818d1d8a..0f314ad96 100644 --- a/src/Tasks/Run.php +++ b/src/Tasks/Run.php @@ -2,15 +2,46 @@ namespace Phabel\Tasks; -use Amp\Parallel\Worker\Environment; -use Amp\Parallel\Worker\Task; +use Phabel\Amp\Parallel\Worker\Environment; +use Phabel\Amp\Parallel\Worker\Task; use Phabel\ExceptionWrapper; use Phabel\Traverser; - class Run implements Task { - public function __construct(private string $relative, private string $input, private string $output, private ?string $package, private string $coverage) + public function __construct(private $relative, private $input, private $output, private $package, private $coverage) { + if (!\is_string($relative)) { + if (!(\is_string($relative) || \is_object($relative) && \method_exists($relative, '__toString') || (\is_bool($relative) || \is_numeric($relative)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($relative) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($relative) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $relative = (string) $relative; + } + if (!\is_string($input)) { + if (!(\is_string($input) || \is_object($input) && \method_exists($input, '__toString') || (\is_bool($input) || \is_numeric($input)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($input) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($input) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $input = (string) $input; + } + if (!\is_string($output)) { + if (!(\is_string($output) || \is_object($output) && \method_exists($output, '__toString') || (\is_bool($output) || \is_numeric($output)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($output) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($output) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $output = (string) $output; + } + if (!\is_null($package)) { + if (!\is_string($package)) { + if (!(\is_string($package) || \is_object($package) && \method_exists($package, '__toString') || (\is_bool($package) || \is_numeric($package)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($package) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($package) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $package = (string) $package; + } + } + if (!\is_string($coverage)) { + if (!(\is_string($coverage) || \is_object($coverage) && \method_exists($coverage, '__toString') || (\is_bool($coverage) || \is_numeric($coverage)))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($coverage) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($coverage) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $coverage = (string) $coverage; + } } public function run(Environment $environment) { @@ -20,7 +51,9 @@ public function run(Environment $environment) $traverser = $environment->get(Traverser::class); $traverser->setPackage($this->package); return $traverser->traverse($this->relative, $this->input, $this->output); - } catch (\Throwable $e) { + } catch (\Exception $e) { + return new ExceptionWrapper($e); + } catch (\Error $e) { return new ExceptionWrapper($e); } } diff --git a/src/Tasks/Shutdown.php b/src/Tasks/Shutdown.php index 0662181da..f23db593b 100644 --- a/src/Tasks/Shutdown.php +++ b/src/Tasks/Shutdown.php @@ -2,10 +2,9 @@ namespace Phabel\Tasks; -use Amp\Parallel\Worker\Environment; -use Amp\Parallel\Worker\Task; +use Phabel\Amp\Parallel\Worker\Environment; +use Phabel\Amp\Parallel\Worker\Task; use Phabel\Traverser; - class Shutdown implements Task { public function run(Environment $environment) diff --git a/src/Tools.php b/src/Tools.php index a405c3d3a..7a143c4c8 100644 --- a/src/Tools.php +++ b/src/Tools.php @@ -2,39 +2,38 @@ namespace Phabel; -use PhpParser\Node; -use PhpParser\Node\Arg; -use PhpParser\Node\Expr; -use PhpParser\Node\Expr\ArrayDimFetch; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Expr\AssignOp; -use PhpParser\Node\Expr\AssignRef; -use PhpParser\Node\Expr\Cast\String_; -use PhpParser\Node\Expr\Clone_; -use PhpParser\Node\Expr\Eval_; -use PhpParser\Node\Expr\FuncCall; -use PhpParser\Node\Expr\Include_; -use PhpParser\Node\Expr\List_; -use PhpParser\Node\Expr\MethodCall; -use PhpParser\Node\Expr\New_; -use PhpParser\Node\Expr\NullsafeMethodCall; -use PhpParser\Node\Expr\NullsafePropertyFetch; -use PhpParser\Node\Expr\PostDec; -use PhpParser\Node\Expr\PostInc; -use PhpParser\Node\Expr\PreDec; -use PhpParser\Node\Expr\PreInc; -use PhpParser\Node\Expr\PropertyFetch; -use PhpParser\Node\Expr\ShellExec; -use PhpParser\Node\Expr\StaticCall; -use PhpParser\Node\Expr\Variable; -use PhpParser\Node\Expr\Yield_; -use PhpParser\Node\Expr\YieldFrom; -use PhpParser\Node\Name; -use PhpParser\Node\Name\FullyQualified; -use PhpParser\Node\Stmt\Expression; -use PhpParser\ParserFactory; +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Node\Arg; +use Phabel\PhpParser\Node\Expr; +use Phabel\PhpParser\Node\Expr\ArrayDimFetch; +use Phabel\PhpParser\Node\Expr\Assign; +use Phabel\PhpParser\Node\Expr\AssignOp; +use Phabel\PhpParser\Node\Expr\AssignRef; +use Phabel\PhpParser\Node\Expr\Cast\String_; +use Phabel\PhpParser\Node\Expr\Clone_; +use Phabel\PhpParser\Node\Expr\Eval_; +use Phabel\PhpParser\Node\Expr\FuncCall; +use Phabel\PhpParser\Node\Expr\Include_; +use Phabel\PhpParser\Node\Expr\List_; +use Phabel\PhpParser\Node\Expr\MethodCall; +use Phabel\PhpParser\Node\Expr\New_; +use Phabel\PhpParser\Node\Expr\NullsafeMethodCall; +use Phabel\PhpParser\Node\Expr\NullsafePropertyFetch; +use Phabel\PhpParser\Node\Expr\PostDec; +use Phabel\PhpParser\Node\Expr\PostInc; +use Phabel\PhpParser\Node\Expr\PreDec; +use Phabel\PhpParser\Node\Expr\PreInc; +use Phabel\PhpParser\Node\Expr\PropertyFetch; +use Phabel\PhpParser\Node\Expr\ShellExec; +use Phabel\PhpParser\Node\Expr\StaticCall; +use Phabel\PhpParser\Node\Expr\Variable; +use Phabel\PhpParser\Node\Expr\Yield_; +use Phabel\PhpParser\Node\Expr\YieldFrom; +use Phabel\PhpParser\Node\Name; +use Phabel\PhpParser\Node\Name\FullyQualified; +use Phabel\PhpParser\Node\Stmt\Expression; +use Phabel\PhpParser\ParserFactory; use ReflectionClass; - /** * Various tools. * @@ -57,20 +56,39 @@ abstract class Tools * * @return Node */ - public static function replaceType(Node $node, string $class, array $propertyMap = []): Node + public static function replaceType(Node $node, $class, array $propertyMap = []) { + if (!\is_string($class)) { + if (!(\is_string($class) || \is_object($class) && \method_exists($class, '__toString') || (\is_bool($class) || \is_numeric($class)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($class) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($class) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $class = (string) $class; + } if ($propertyMap) { $nodeNew = (new ReflectionClass($class))->newInstanceWithoutConstructor(); foreach ($propertyMap as $old => $new) { $nodeNew->{$new} = $node->{$old}; } $nodeNew->setAttributes($node->getAttributes()); - return $nodeNew; + $phabelReturn = $nodeNew; + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = new $class(...\array_merge(\array_map(function ($name) use($node) { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $name = (string) $name; + } + return $node->{$name}; + }, $node->getSubNodeNames()), [$node->getAttributes()])); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return new $class(...[ - ...\array_map(fn (string $name) => $node->{$name}, $node->getSubNodeNames()), - $node->getAttributes() - ]); + return $phabelReturn; } /** * Replace type in-place. @@ -86,8 +104,14 @@ public static function replaceType(Node $node, string $class, array $propertyMap * * @return void */ - public static function replaceTypeInPlace(Node &$node, string $class, array $propertyMap = []): void + public static function replaceTypeInPlace(Node &$node, $class, array $propertyMap = []) { + if (!\is_string($class)) { + if (!(\is_string($class) || \is_object($class) && \method_exists($class, '__toString') || (\is_bool($class) || \is_numeric($class)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($class) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($class) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $class = (string) $class; + } $node = self::replaceType($node, $class, $propertyMap); } /** @@ -98,14 +122,13 @@ public static function replaceTypeInPlace(Node &$node, string $class, array $pro * * @return Expression */ - public static function assign(Variable $name, Expr $expression): Expression + public static function assign(Variable $name, Expr $expression) { - return new Expression( - new Assign( - $name, - $expression - ) - ); + $phabelReturn = new Expression(new Assign($name, $expression)); + if (!$phabelReturn instanceof Expression) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expression, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Call function. @@ -122,10 +145,10 @@ public static function assign(Variable $name, Expr $expression): Expression */ public static function call($name, ...$parameters) { - $parameters = \array_map(fn ($data) => $data instanceof Arg ? $data : new Arg($data), $parameters); - return \is_array($name) - ? new StaticCall(new FullyQualified($name[0]), $name[1], $parameters) - : new FuncCall(new FullyQualified($name), $parameters); + $parameters = \array_map(function ($data) { + return $data instanceof Arg ? $data : new Arg($data); + }, $parameters); + return \is_array($name) ? new StaticCall(new FullyQualified($name[0]), $name[1], $parameters) : new FuncCall(new FullyQualified($name), $parameters); } /** * Call method of object. @@ -136,10 +159,22 @@ public static function call($name, ...$parameters) * * @return MethodCall */ - public static function callMethod(Expr $name, string $method, ...$parameters): MethodCall + public static function callMethod(Expr $name, $method, ...$parameters) { - $parameters = \array_map(fn ($data) => $data instanceof Arg ? $data : new Arg($data), $parameters); - return new MethodCall($name, $method, $parameters); + if (!\is_string($method)) { + if (!(\is_string($method) || \is_object($method) && \method_exists($method, '__toString') || (\is_bool($method) || \is_numeric($method)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($method) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($method) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $method = (string) $method; + } + $parameters = \array_map(function ($data) { + return $data instanceof Arg ? $data : new Arg($data); + }, $parameters); + $phabelReturn = new MethodCall($name, $method, $parameters); + if (!$phabelReturn instanceof MethodCall) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type MethodCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Convert array, int or other literal to node. @@ -148,9 +183,13 @@ public static function callMethod(Expr $name, string $method, ...$parameters): M * * @return Node */ - public static function fromLiteral($data): Node + public static function fromLiteral($data) { - return self::toNode(\var_export($data, true).';'); + $phabelReturn = self::toNode(\var_export($data, \true) . ';'); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Convert code to node. @@ -161,15 +200,24 @@ public static function fromLiteral($data): Node * * @return Node */ - public static function toNode(string $code): Node + public static function toNode($code) { - $res = (new ParserFactory)->create(ParserFactory::PREFER_PHP7)->parse('create(ParserFactory::PREFER_PHP7)->parse('expr)) { throw new \RuntimeException('Invalid code was provided!'); } - return $res[0]->expr; + $phabelReturn = $res[0]->expr; + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Check if this node or any child node have any side effects (like calling other methods, or assigning variables). * @@ -177,59 +225,72 @@ public static function toNode(string $code): Node * * @return bool */ - public static function hasSideEffects(?Expr $node): bool + public static function hasSideEffects($node) { + if (!($node instanceof Expr || \is_null($node))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($node) must be of type ?Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($node) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } if (!$node) { - return false; - } - if ($node->hasAttribute('hasSideEffects') - || $node instanceof String_ // __toString - || $node instanceof ArrayDimFetch // offsetSet/offsetGet - || $node instanceof Assign - || $node instanceof AssignOp - || $node instanceof AssignRef - || $node instanceof Clone_ // __clone - || $node instanceof Eval_ - || $node instanceof FuncCall - || $node instanceof Include_ - || $node instanceof List_ // offsetGet/offsetSet - || $node instanceof MethodCall - || $node instanceof New_ - || $node instanceof NullsafeMethodCall - || $node instanceof NullsafePropertyFetch - || $node instanceof PostDec - || $node instanceof PostInc - || $node instanceof PreDec - || $node instanceof PreInc - || $node instanceof PropertyFetch - || $node instanceof StaticCall - || $node instanceof Yield_ - || $node instanceof YieldFrom - || $node instanceof ShellExec - ) { - $node->setAttribute('hasSideEffects', true); - return true; + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; + } + if ($node->hasAttribute('hasSideEffects') || $node instanceof String_ || $node instanceof ArrayDimFetch || $node instanceof Assign || $node instanceof AssignOp || $node instanceof AssignRef || $node instanceof Clone_ || $node instanceof Eval_ || $node instanceof FuncCall || $node instanceof Include_ || $node instanceof List_ || $node instanceof MethodCall || $node instanceof New_ || $node instanceof NullsafeMethodCall || $node instanceof NullsafePropertyFetch || $node instanceof PostDec || $node instanceof PostInc || $node instanceof PreDec || $node instanceof PreInc || $node instanceof PropertyFetch || $node instanceof StaticCall || $node instanceof Yield_ || $node instanceof YieldFrom || $node instanceof ShellExec) { + $node->setAttribute('hasSideEffects', \true); + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** @var string */ foreach ($node->getSubNodeNames() as $name) { if ($node->{$name} instanceof Expr) { if (self::hasSideEffects($node->{$name})) { - $node->setAttribute('hasSideEffects', true); - return true; + $node->setAttribute('hasSideEffects', \true); + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } } elseif (\is_array($node->{$name})) { /** @var Node|Node[]|string */ foreach ($node->{$name} as $var) { if ($var instanceof Expr && self::hasSideEffects($var)) { - $node->setAttribute('hasSideEffects', true); - return true; + $node->setAttribute('hasSideEffects', \true); + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } } } } - return false; + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } - /** * Get fully qualified name. * @@ -238,21 +299,55 @@ public static function hasSideEffects(?Expr $node): bool * * @return class-string */ - public static function getFqdn(Node $node, string $alt = ''): string + public static function getFqdn(Node $node, $alt = '') { + if (!\is_string($alt)) { + if (!(\is_string($alt) || \is_object($alt) && \method_exists($alt, '__toString') || (\is_bool($alt) || \is_numeric($alt)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($alt) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($alt) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $alt = (string) $alt; + } if ($node instanceof FullyQualified) { - return (string) $node; + $phabelReturn = (string) $node; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } if (isset($node->namespacedName)) { - return (string) $node->namespacedName; + $phabelReturn = (string) $node->namespacedName; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } if (!$node->getAttribute('resolvedName')) { if ($alt) { - return $alt; + $phabelReturn = $alt; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - throw new UnresolvedNameException(); + throw new \Phabel\UnresolvedNameException(); } - return (string) $node->getAttribute('resolvedName', $node->getAttribute('namespacedName')); + $phabelReturn = (string) $node->getAttribute('resolvedName', $node->getAttribute('namespacedName')); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } /** * Create a new object extended from this object, with the specified additional trait + interface. @@ -265,39 +360,38 @@ public static function getFqdn(Node $node, string $alt = ''): string * * @return object */ - public static function cloneWithTrait(object $obj, string $trait): object + public static function cloneWithTrait($obj, $trait) { + if (!\is_object($obj)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($obj) must be of type object, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($obj) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_string($trait)) { + if (!(\is_string($trait) || \is_object($trait) && \method_exists($trait, '__toString') || (\is_bool($trait) || \is_numeric($trait)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($trait) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($trait) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $trait = (string) $trait; + } /** @psalm-var int */ static $count = 0; /** @psalm-var array> $memoized */ static $memoized = []; - $reflect = new ReflectionClass($obj); - - $r = $reflect; while ($r && $r->isAnonymous()) { $r = $r->getParentClass(); } - - $extend = "extends \\".$r->getName(); - if (isset($memoized["$trait $extend"])) { + $extend = "extends \\" . $r->getName(); + if (isset($memoized["{$trait} {$extend}"])) { /** @psalm-suppress MixedMethodCall */ - $newObj = new $memoized["$trait $extend"]; + $newObj = ($phabel_a2ec9a4ca43bd91b = $memoized["{$trait} {$extend}"]) || \true ? new $phabel_a2ec9a4ca43bd91b() : \false; } else { - $memoized["$trait $extend"] = "phabelTmpClass$count"; - $eval = "class phabelTmpClass$count $extend { - use \\$trait; - public function __construct() {} - } - return new phabelTmpClass$count;"; + $memoized["{$trait} {$extend}"] = "phabelTmpClass{$count}"; + $eval = "class phabelTmpClass{$count} {$extend} {\n use \\{$trait};\n public function __construct() {}\n }\n return new phabelTmpClass{$count};"; $count++; /** @var object */ $newObj = eval($eval); } - $reflectNew = new ReflectionClass($newObj); - do { if ($tmp = $reflectNew->getParentClass()) { $reflectNew = $tmp; @@ -305,16 +399,18 @@ public function __construct() {} foreach ($reflect->getProperties() as $prop) { if ($reflectNew->hasProperty($prop->getName())) { $propNew = $reflectNew->getProperty($prop->getName()); - $propNew->setAccessible(true); - $prop->setAccessible(true); + $propNew->setAccessible(\true); + $prop->setAccessible(\true); $propNew->setValue($newObj, $prop->getValue($obj)); } } } while ($reflect = $reflect->getParentClass()); - - return $newObj; + $phabelReturn = $newObj; + if (!\is_object($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type object, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Checks private property exists in an object. * @@ -330,15 +426,34 @@ public function __construct() {} * @return bool * @access public */ - public static function hasVar(object $obj, string $var): bool + public static function hasVar($obj, $var) { - return \Closure::bind( - function () use ($var): bool { - return isset($this->{$var}); - }, - $obj, - \get_class($obj) - )->__invoke(); + if (!\is_object($obj)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($obj) must be of type object, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($obj) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_string($var)) { + if (!(\is_string($var) || \is_object($var) && \method_exists($var, '__toString') || (\is_bool($var) || \is_numeric($var)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($var) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($var) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $var = (string) $var; + } + $phabelReturn = \Closure::bind(function () use($var) { + $phabelReturn = isset($this->{$var}); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; + }, $obj, \get_class($obj))->__invoke(); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * Accesses a private variable from an object. @@ -353,11 +468,17 @@ function () use ($var): bool { * @return mixed * @access public */ - public static function &getVar($obj, string $var) + public static function &getVar($obj, $var) { + if (!\is_string($var)) { + if (!(\is_string($var) || \is_object($var) && \method_exists($var, '__toString') || (\is_bool($var) || \is_numeric($var)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($var) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($var) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $var = (string) $var; + } return \Closure::bind( /** @return mixed */ - function & () use ($var) { + function &() use($var) { return $this->{$var}; }, $obj, @@ -378,17 +499,18 @@ function & () use ($var) { * * @access public */ - public static function setVar($obj, string $var, &$val): void + public static function setVar($obj, $var, &$val) { - \Closure::bind( - function () use ($var, &$val) { - $this->{$var} =& $val; - }, - $obj, - \get_class($obj) - )->__invoke(); + if (!\is_string($var)) { + if (!(\is_string($var) || \is_object($var) && \method_exists($var, '__toString') || (\is_bool($var) || \is_numeric($var)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($var) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($var) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $var = (string) $var; + } + \Closure::bind(function () use($var, &$val) { + $this->{$var} =& $val; + }, $obj, \get_class($obj))->__invoke(); } - /** * Adapted from https://gist.github.com/divinity76/01ef9ca99c111565a72d3a8a6e42f7fb * returns number of cpu cores @@ -397,13 +519,27 @@ function () use ($var, &$val) { * @throws \LogicException * @psalm-suppress ForbiddenCode */ - public static function getCpuCount(): int + public static function getCpuCount() { static $result = -1; if ($result !== -1) { - return $result; + $phabelReturn = $result; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } if (\defined('PHP_WINDOWS_VERSION_MAJOR')) { + $phabelReturn = $result = 1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } /* $str = trim((string) shell_exec('wmic cpu get NumberOfCores 2>&1')); if (!preg_match('/(\d+)/', $str, $matches)) { @@ -411,51 +547,83 @@ public static function getCpuCount(): int } return ((int) $matches [1]); */ - return $result = 1; + return $phabelReturn; } - - if (self::ini_get('pcre.jit') === '1' - && \PHP_OS === 'Darwin' - && \version_compare(\PHP_VERSION, '7.3.0') >= 0 - && \version_compare(\PHP_VERSION, '7.4.0') < 0 - ) { - return $result = 1; + if (self::ini_get('pcre.jit') === '1' && \PHP_OS === 'Darwin' && \version_compare(\PHP_VERSION, '7.3.0') >= 0 && \version_compare(\PHP_VERSION, '7.4.0') < 0) { + $phabelReturn = $result = 1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - if (!\extension_loaded('pcntl')) { - return $result = 1; + $phabelReturn = $result = 1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - $has_nproc = \trim((string) @\shell_exec('command -v nproc')); if ($has_nproc) { $ret = @\shell_exec('nproc'); if (\is_string($ret)) { $ret = \trim($ret); - $tmp = \filter_var($ret, FILTER_VALIDATE_INT); + $tmp = \filter_var($ret, \FILTER_VALIDATE_INT); if (\is_int($tmp)) { - return $result = $tmp; + $phabelReturn = $result = $tmp; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } } } - $ret = @\shell_exec('sysctl -n hw.ncpu'); if (\is_string($ret)) { $ret = \trim($ret); - $tmp = \filter_var($ret, FILTER_VALIDATE_INT); + $tmp = \filter_var($ret, \FILTER_VALIDATE_INT); if (\is_int($tmp)) { - return $result = $tmp; + $phabelReturn = $result = $tmp; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } } - if (\is_readable('/proc/cpuinfo')) { $cpuinfo = \file_get_contents('/proc/cpuinfo'); $count = \substr_count($cpuinfo, 'processor'); if ($count > 0) { - return $result = $count; + $phabelReturn = $result = $count; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } } - - return $result = 1; + $phabelReturn = $result = 1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } /** * Safely get value from php.ini. @@ -464,13 +632,20 @@ public static function getCpuCount(): int * @param mixed $default * @return mixed */ - public static function ini_get(string $key, $default = null) + public static function ini_get($key, $default = null) { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $key = (string) $key; + } try { if (\function_exists('ini_get')) { return @\ini_get($key); } - } catch (\Throwable $e) { + } catch (\Exception $e) { + } catch (\Error $e) { } return $default; } diff --git a/src/Traverser.php b/src/Traverser.php index ce5c4f6d9..4bc2c6411 100644 --- a/src/Traverser.php +++ b/src/Traverser.php @@ -2,27 +2,25 @@ namespace Phabel; -use Amp\Parallel\Worker\DefaultPool; -use Amp\Promise; +use Phabel\Amp\Parallel\Worker\DefaultPool; +use Phabel\Amp\Promise; use Phabel\Plugin\ClassStoragePlugin; use Phabel\PluginGraph\Graph; use Phabel\PluginGraph\ResolvedGraph; use Phabel\Tasks\Init; use Phabel\Tasks\Run; use Phabel\Tasks\Shutdown; -use PhpParser\Node; -use PhpParser\Parser; -use PhpParser\ParserFactory; -use PhpParser\PrettyPrinter\Standard; -use SebastianBergmann\CodeCoverage\CodeCoverage; -use SebastianBergmann\CodeCoverage\Driver\Selector; -use SebastianBergmann\CodeCoverage\Filter; -use SebastianBergmann\CodeCoverage\Report\PHP; +use Phabel\PhpParser\Node; +use Phabel\PhpParser\Parser; +use Phabel\PhpParser\ParserFactory; +use Phabel\PhpParser\PrettyPrinter\Standard; +use Phabel\SebastianBergmann\CodeCoverage\CodeCoverage; +use Phabel\SebastianBergmann\CodeCoverage\Driver\Selector; +use Phabel\SebastianBergmann\CodeCoverage\Filter; +use Phabel\SebastianBergmann\CodeCoverage\Report\PHP; use SplQueue; - -use function Amp\call; -use function Amp\Promise\wait; - +use function Phabel\Amp\call; +use function Phabel\Amp\Promise\wait; /** * AST traverser. * @@ -36,43 +34,43 @@ class Traverser * * @var ResolvedGraph */ - private ResolvedGraph $graph; + private $graph; /** * Parser instance. */ - private Parser $parser; + private $parser; /** * Printer instance. */ - private Standard $printer; + private $printer; /** * Plugin queue for specific package. * * @var SplQueue>|null */ - private ?SplQueue $packageQueue = null; + private $packageQueue = null; /** * Event handler. * * @var EventHandlerInterface|null */ - private ?EventHandlerInterface $eventHandler = null; + private $eventHandler = null; /** * Input. * * @var string */ - private string $input = ''; + private $input = ''; /** * Output. * * @var string */ - private string $output = ''; + private $output = ''; /** * File whitelist. */ - private ?array $fileWhitelist = null; + private $fileWhitelist = null; /** * Callable to extract package name from path. * @@ -84,26 +82,25 @@ class Traverser * * @var string */ - private string $coverage = ''; + private $coverage = ''; /** * Current file. */ - private string $file = ''; + private $file = ''; /** * Current input file. */ - private string $inputFile = ''; + private $inputFile = ''; /** * Current output file. */ - private string $outputFile = ''; - + private $outputFile = ''; /** * Number of times we traversed directories. * * @var integer */ - private int $count = 0; + private $count = 0; /** * Generate traverser from basic plugin instances. * @@ -111,31 +108,36 @@ class Traverser * * @return self */ - public static function fromPlugin(Plugin ...$plugin): self + public static function fromPlugin(\Phabel\Plugin ...$plugin) { - $queue = new SplQueue; + $queue = new SplQueue(); foreach ($plugin as $p) { $queue->enqueue($p); } - $final = new SplQueue; + $final = new SplQueue(); $final->enqueue($queue); $res = new self(); $res->graph = new ResolvedGraph($final); - return $res; + $phabelReturn = $res; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Constructor. * * @param ?EventHandlerInterface $EventHandlerInterface Event handler */ - public function __construct(?EventHandlerInterface $eventHandler = null) + public function __construct($eventHandler = null) { - $this->parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); + if (!($eventHandler instanceof \Phabel\EventHandlerInterface || \is_null($eventHandler))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($eventHandler) must be of type ?EventHandlerInterface, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($eventHandler) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $this->parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7); $this->printer = new Standard(); $this->eventHandler = $eventHandler; } - /** * Set plugin array. * @@ -145,20 +147,20 @@ public function __construct(?EventHandlerInterface $eventHandler = null) * * @return self */ - public function setPlugins(array $plugins): self + public function setPlugins(array $plugins) { - $this->eventHandler?->onBeginPluginGraphResolution(); - - $graph = new Graph; + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onBeginPluginGraphResolution(); + $graph = new Graph(); foreach ($plugins as $plugin => $config) { $graph->addPlugin($plugin, $config, $graph->getPackageContext()); } - $this->graph = $graph->flatten(); - - $this->eventHandler?->onEndPluginGraphResolution(); - - return $this; + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onEndPluginGraphResolution(); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Set plugin graph. @@ -167,27 +169,30 @@ public function setPlugins(array $plugins): self * * @return self */ - public function setPluginGraph(Graph $graph): self + public function setPluginGraph(Graph $graph) { - $this->eventHandler?->onBeginPluginGraphResolution(); - + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onBeginPluginGraphResolution(); $this->graph = $graph->flatten(); - - $this->eventHandler?->onEndPluginGraphResolution(); - - return $this; + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onEndPluginGraphResolution(); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Get resolved plugin graph. * * @return ResolvedGraph */ - public function getGraph(): ResolvedGraph + public function getGraph() { - return $this->graph; + $phabelReturn = $this->graph; + if (!$phabelReturn instanceof ResolvedGraph) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ResolvedGraph, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Set resolved plugin graph. * @@ -195,27 +200,38 @@ public function getGraph(): ResolvedGraph * * @return self */ - public function setGraph(ResolvedGraph $graph): self + public function setGraph(ResolvedGraph $graph) { $this->graph = $graph; - - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Set input path. * * @param string $input * @return self */ - public function setInput(string $input): self + public function setInput($input) { + if (!\is_string($input)) { + if (!(\is_string($input) || \is_object($input) && \method_exists($input, '__toString') || (\is_bool($input) || \is_numeric($input)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($input) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($input) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $input = (string) $input; + } if (!\file_exists($input)) { throw new \RuntimeException("File {$input} does not exist!"); } - $this->input = $input; - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Set output path. @@ -223,12 +239,21 @@ public function setInput(string $input): self * @param string $output * @return self */ - public function setOutput(string $output): self + public function setOutput($output) { + if (!\is_string($output)) { + if (!(\is_string($output) || \is_object($output) && \method_exists($output, '__toString') || (\is_bool($output) || \is_numeric($output)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($output) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($output) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $output = (string) $output; + } $this->output = $output; - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Set callable to extract composer package name from path. * @@ -236,23 +261,35 @@ public function setOutput(string $output): self * * @return self */ - public function setComposer(callable $composer): self + public function setComposer(callable $composer) { $this->composerPackageName = $composer; - - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - /** * Set coverage path. * * @param string $coverage * @return self */ - public function setCoverage(string $coverage): self + public function setCoverage($coverage) { + if (!\is_string($coverage)) { + if (!(\is_string($coverage) || \is_object($coverage) && \method_exists($coverage, '__toString') || (\is_bool($coverage) || \is_numeric($coverage)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($coverage) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($coverage) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $coverage = (string) $coverage; + } $this->coverage = $coverage; - return $this; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Start code coverage. @@ -261,95 +298,103 @@ public function setCoverage(string $coverage): self * * @return ?object */ - public static function startCoverage(string $coveragePath): ?object + public static function startCoverage($coveragePath) { + if (!\is_string($coveragePath)) { + if (!(\is_string($coveragePath) || \is_object($coveragePath) && \method_exists($coveragePath, '__toString') || (\is_bool($coveragePath) || \is_numeric($coveragePath)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($coveragePath) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($coveragePath) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $coveragePath = (string) $coveragePath; + } if (!$coveragePath || !\class_exists(CodeCoverage::class)) { - return null; + $phabelReturn = null; + if (!(\is_object($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?object, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } try { - $filter = new Filter; - $filter->includeDirectory(\realpath(__DIR__.'/../src')); - - $coverage = new CodeCoverage( - (new Selector)->forLineCoverage($filter), - $filter - ); + $filter = new Filter(); + $filter->includeDirectory(\realpath(__DIR__ . '/../src')); + $coverage = new CodeCoverage((new Selector())->forLineCoverage($filter), $filter); $coverage->start('phabel'); - - return new class($coverage, $coveragePath) { - private string $coveragePath; - private CodeCoverage $coverage; - public function __construct(CodeCoverage $coverage, string $coveragePath) - { - $this->coverage = $coverage; - $this->coveragePath = $coveragePath; - } - public function __destruct() - { - $this->coverage->stop(); - if (\file_exists($this->coveragePath)) { - $this->coverage->merge(require $this->coveragePath); - } - (new PHP)->process($this->coverage, $this->coveragePath); - } - }; - } catch (\Throwable $e) { + $phabelReturn = new \Phabel\PhabelAnonymousClass063d10f883fe83b0c12eba721edc03b9cc7383d4550ab4363c290322abe45bb50($coverage, $coveragePath); + if (!(\is_object($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?object, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } catch (\Exception $e) { + } catch (\Error $e) { } - return null; + $phabelReturn = null; + if (!(\is_object($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?object, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Run phabel asynchronously. * * @return array */ - public function runAsync(int $threads = -1): array + public function runAsync($threads = -1) { - return wait($this->runAsyncPromise($threads)); + if (!\is_int($threads)) { + if (!(\is_bool($threads) || \is_numeric($threads))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($threads) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($threads) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $threads = (int) $threads; + } + $phabelReturn = wait($this->runAsyncPromise($threads)); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Run phabel asynchronously. * * @return Promise */ - public function runAsyncPromise(int $threads = -1): Promise + public function runAsyncPromise($threads = -1) { + if (!\is_int($threads)) { + if (!(\is_bool($threads) || \is_numeric($threads))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($threads) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($threads) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $threads = (int) $threads; + } if (!\interface_exists(Promise::class)) { - throw new Exception("amphp/parallel must be installed to parallelize transforms!"); + throw new \Phabel\Exception("amphp/parallel must be installed to parallelize transforms!"); } - $this->eventHandler?->onStart(); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onStart(); if ($threads === -1) { - $threads = Tools::getCpuCount(); + $threads = \Phabel\Tools::getCpuCount(); } $coverages = []; - return call(function () use (&$coverages, $threads) { + $phabelReturn = call(function () use(&$coverages, $threads) { $packages = []; $first = !$this->count++; - if (!\file_exists($this->output)) { - \mkdir($this->output, 0777, true); + \mkdir($this->output, 0777, \true); } $output = \realpath($this->output); - $count = 0; $promises = []; $classStorage = null; - $pool = new DefaultPool($threads); $promises = []; for ($x = 0; $x < $threads; $x++) { - $promises []= $pool->enqueue(new Init($this->graph)); + $promises[] = $pool->enqueue(new Init($this->graph)); } - yield $promises; + (yield $promises); $packages = $this->graph->getPackages(); unset($this->graph); - $it = new \RecursiveDirectoryIterator($this->input, \RecursiveDirectoryIterator::SKIP_DOTS); $ri = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::SELF_FIRST); - if ($this->eventHandler) { $this->eventHandler->onBeginDirectoryTraversal($this->fileWhitelist ? \count($this->fileWhitelist) : \iterator_count($ri), $threads); } - $promises = []; /** @var \SplFileInfo $file */ foreach ($ri as $file) { @@ -357,32 +402,25 @@ public function runAsyncPromise(int $threads = -1): Promise if ($this->fileWhitelist && !isset($this->fileWhitelist[$rel])) { continue; } - $targetPath = $output.DIRECTORY_SEPARATOR.$rel; + $targetPath = $output . \DIRECTORY_SEPARATOR . $rel; if ($file->isDir()) { if (!\file_exists($targetPath)) { - \mkdir($targetPath, 0777, true); + \mkdir($targetPath, 0777, \true); } } elseif ($file->isFile()) { if ($file->getExtension() == 'php') { - $promise = call(function () use ($pool, $file, $rel, $targetPath, $count, $first, &$promises, &$coverages) { - $this->eventHandler?->onBeginAstTraversal($file->getRealPath()); + $promise = call(function () use($pool, $file, $rel, $targetPath, $count, $first, &$promises, &$coverages) { + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onBeginAstTraversal($file->getRealPath()); $package = null; if ($this->composerPackageName) { - $package = ($this->composerPackageName)($rel); + $phabel_c507848c74a74245 = $this->composerPackageName; + $package = $phabel_c507848c74a74245($rel); } - $res = yield $pool->enqueue( - new Run( - $rel, - $file->getRealPath(), - $targetPath, - $package, - $this->coverage ? "{$this->coverage}$count.php" : '' - ) - ); + $res = (yield $pool->enqueue(new Run($rel, $file->getRealPath(), $targetPath, $package, $this->coverage ? "{$this->coverage}{$count}.php" : ''))); if ($this->coverage) { - $coverages []= "{$this->coverage}$count.php"; + $coverages[] = "{$this->coverage}{$count}.php"; } - if ($res instanceof ExceptionWrapper) { + if ($res instanceof \Phabel\ExceptionWrapper) { $res = $res->getException(); if (!($first && \str_contains($res->getMessage(), ' while parsing '))) { throw $res; @@ -392,7 +430,7 @@ public function runAsyncPromise(int $threads = -1): Promise } } \chmod($targetPath, \fileperms($file->getRealPath())); - $this->eventHandler?->onEndAstTraversal($file->getRealPath(), $res); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onEndAstTraversal($file->getRealPath(), $res); unset($promises[$count]); }); $promises[$count] = $promise; @@ -403,34 +441,30 @@ public function runAsyncPromise(int $threads = -1): Promise } } } - yield $promises; - - $this->eventHandler?->onEndDirectoryTraversal(); - $this->eventHandler?->onBeginClassGraphMerge($threads); - + (yield $promises); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onEndDirectoryTraversal(); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onBeginClassGraphMerge($threads); $promises = []; /** @var ClassStoragePlugin|null */ $classStorage = null; for ($x = 0; $x < $threads; $x++) { - $promises []= call(function () use ($pool, &$classStorage) { + $promises[] = call(function () use($pool, &$classStorage) { /** @var ClassStoragePlugin */ - $newClassStorage = yield $pool->enqueue(new Shutdown()); + $newClassStorage = (yield $pool->enqueue(new Shutdown())); if (!$classStorage) { $classStorage = $newClassStorage; } else { $classStorage->merge($newClassStorage); } - $this->eventHandler?->onClassGraphMerged(); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onClassGraphMerged(); }); } - yield $promises; - $this->eventHandler?->onEndClassGraphMerge(); - - yield $pool->shutdown(); + (yield $promises); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onEndClassGraphMerge(); + (yield $pool->shutdown()); unset($pool); - if ($classStorage) { - [$plugins, $files] = $classStorage->finish(); + list($plugins, $files) = $classStorage->finish(); unset($classStorage); if ($plugins && $files) { $this->input = $this->output; @@ -440,7 +474,6 @@ public function runAsyncPromise(int $threads = -1): Promise return $this->run(); } } - /** @var CodeCoverage|null $coverage */ $coverage = null; foreach ($coverages as $file) { @@ -449,7 +482,7 @@ public function runAsyncPromise(int $threads = -1): Promise } if (!$coverage) { /** @var CodeCoverage $coverage */ - $coverage = include $file; + $coverage = (include $file); \unlink($file); continue; } @@ -457,46 +490,85 @@ public function runAsyncPromise(int $threads = -1): Promise \unlink($file); } if ($coverage) { - (new PHP)->process($coverage, $this->coverage); + (new PHP())->process($coverage, $this->coverage); } - - $this->eventHandler?->onEnd(); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onEnd(); return $packages; }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - - /** * Run phabel. * * @return array */ - public function run(int $threads = 1): array + public function run($threads = 1) { + if (!\is_int($threads)) { + if (!(\is_bool($threads) || \is_numeric($threads))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($threads) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($threads) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $threads = (int) $threads; + } if ($threads > 1 || $threads === -1) { - return $this->runAsync($threads); + $phabelReturn = $this->runAsync($threads); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } - \set_error_handler( - function (int $errno = 0, string $errstr = '', string $errfile = '', int $errline = -1): bool { - // If error is suppressed with @, don't throw an exception - if (\error_reporting() === 0) { - return false; + \set_error_handler(function ($errno = 0, $errstr = '', $errfile = '', $errline = -1) { + if (!\is_int($errno)) { + if (!(\is_bool($errno) || \is_numeric($errno))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($errno) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($errno) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - throw new Exception($errstr, $errno, null, $errfile, $errline); + $errno = (int) $errno; } - ); - + if (!\is_string($errstr)) { + if (!(\is_string($errstr) || \is_object($errstr) && \method_exists($errstr, '__toString') || (\is_bool($errstr) || \is_numeric($errstr)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($errstr) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($errstr) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $errstr = (string) $errstr; + } + if (!\is_string($errfile)) { + if (!(\is_string($errfile) || \is_object($errfile) && \method_exists($errfile, '__toString') || (\is_bool($errfile) || \is_numeric($errfile)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($errfile) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($errfile) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $errfile = (string) $errfile; + } + if (!\is_int($errline)) { + if (!(\is_bool($errline) || \is_numeric($errline))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($errline) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($errline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $errline = (int) $errline; + } + // If error is suppressed with @, don't throw an exception + if (\error_reporting() === 0) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; + } + throw new \Phabel\Exception($errstr, $errno, null, $errfile, $errline); + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + }); $packages = []; - - $this->eventHandler?->onStart(); - while (true) { + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onStart(); + while (\true) { $this->runInternal(); $packages += $this->graph->getPackages(); $classStorage = $this->graph->getClassStorage(); if (!$classStorage) { break; } - [$plugins, $files] = $classStorage->finish(); + list($plugins, $files) = $classStorage->finish(); unset($classStorage); if (!$plugins || !$files) { break; @@ -506,33 +578,32 @@ function (int $errno = 0, string $errstr = '', string $errfile = '', int $errlin $this->composerPackageName = null; $this->setPlugins($plugins); } - $this->eventHandler?->onEnd(); - + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onEnd(); \restore_error_handler(); - - return $packages; + $phabelReturn = $packages; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Run phabel (internal function). * * @internal */ - public function runInternal(): void + public function runInternal() { $_ = self::startCoverage($this->coverage); $first = !$this->count++; $this->packageQueue = null; - if (\is_file($this->input)) { $this->traverse(\basename($this->input), \realpath($this->input), \realpath($this->output) ?: $this->output); return; } - if (!\file_exists($this->output)) { - \mkdir($this->output, 0777, true); + \mkdir($this->output, 0777, \true); } $this->output = \realpath($this->output); - $it = new \RecursiveDirectoryIterator($this->input, \RecursiveDirectoryIterator::SKIP_DOTS); $ri = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::SELF_FIRST); if ($this->eventHandler) { @@ -544,29 +615,38 @@ public function runInternal(): void if ($this->fileWhitelist && !isset($this->fileWhitelist[$rel])) { continue; } - $targetPath = $this->output.DIRECTORY_SEPARATOR.$rel; + $targetPath = $this->output . \DIRECTORY_SEPARATOR . $rel; if ($file->isDir()) { if (!\file_exists($targetPath)) { - \mkdir($targetPath, 0777, true); + \mkdir($targetPath, 0777, \true); } } elseif ($file->isFile()) { if ($file->getExtension() == 'php') { $_ = self::startCoverage($this->coverage); if ($this->composerPackageName) { - $this->setPackage(($this->composerPackageName)($rel)); + $phabel_b1a55408243b319b = $this->composerPackageName; + $this->setPackage($phabel_b1a55408243b319b($rel)); } else { $this->packageQueue = null; } try { $it = $this->traverse($rel, $file->getRealPath(), $targetPath); - } catch (\Throwable $e) { - if (!($first && $e instanceof Exception && \str_contains($e->getMessage(), ' while parsing '))) { + } catch (\Exception $e) { + if (!($first && $e instanceof \Phabel\Exception && \str_contains($e->getMessage(), ' while parsing '))) { + throw $e; + } + if (\realpath($targetPath) !== $file->getRealPath()) { + \copy($file->getRealPath(), $targetPath); + } + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onEndAstTraversal($file->getRealPath(), $e); + } catch (\Error $e) { + if (!($first && $e instanceof \Phabel\Exception && \str_contains($e->getMessage(), ' while parsing '))) { throw $e; } if (\realpath($targetPath) !== $file->getRealPath()) { \copy($file->getRealPath(), $targetPath); } - $this->eventHandler?->onEndAstTraversal($file->getRealPath(), $e); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onEndAstTraversal($file->getRealPath(), $e); } } elseif (\realpath($targetPath) !== $file->getRealPath()) { \copy($file->getRealPath(), $targetPath); @@ -574,9 +654,8 @@ public function runInternal(): void \chmod($targetPath, \fileperms($file->getRealPath())); } } - $this->eventHandler?->onEndDirectoryTraversal(); + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onEndDirectoryTraversal(); } - /** * Set package name. * @@ -584,21 +663,29 @@ public function runInternal(): void * * @return void */ - public function setPackage(?string $package): void + public function setPackage($package) { + if (!\is_null($package)) { + if (!\is_string($package)) { + if (!(\is_string($package) || \is_object($package) && \method_exists($package, '__toString') || (\is_bool($package) || \is_numeric($package)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($package) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($package) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $package = (string) $package; + } + } /** @var SplQueue> */ if (!$package) { $this->packageQueue = null; return; } - $this->packageQueue = new SplQueue; + $this->packageQueue = new SplQueue(); /** @var SplQueue */ - $newQueue = new SplQueue; + $newQueue = new SplQueue(); foreach ($this->graph->getPlugins() as $queue) { if ($newQueue->count()) { $this->packageQueue->enqueue($newQueue); /** @var SplQueue */ - $newQueue = new SplQueue; + $newQueue = new SplQueue(); } /** @var Plugin */ foreach ($queue as $plugin) { @@ -620,19 +707,36 @@ public function setPackage(?string $package): void * * @return int */ - public function traverse(string $file, string $input, string $output): int + public function traverse($file, $input, $output) { - $this->eventHandler?->onBeginAstTraversal($input); - + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($file) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $file = (string) $file; + } + if (!\is_string($input)) { + if (!(\is_string($input) || \is_object($input) && \method_exists($input, '__toString') || (\is_bool($input) || \is_numeric($input)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($input) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($input) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $input = (string) $input; + } + if (!\is_string($output)) { + if (!(\is_string($output) || \is_object($output) && \method_exists($output, '__toString') || (\is_bool($output) || \is_numeric($output)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($output) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($output) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $output = (string) $output; + } + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onBeginAstTraversal($input); /** @var SplQueue> */ - $reducedQueue = new SplQueue; + $reducedQueue = new SplQueue(); /** @var SplQueue */ - $newQueue = new SplQueue; - foreach ($this->packageQueue ?? $this->graph->getPlugins() as $queue) { + $newQueue = new SplQueue(); + foreach (isset($this->packageQueue) ? $this->packageQueue : $this->graph->getPlugins() as $queue) { if ($newQueue->count()) { $reducedQueue->enqueue($newQueue); /** @var SplQueue */ - $newQueue = new SplQueue; + $newQueue = new SplQueue(); } /** @var Plugin */ foreach ($queue as $plugin) { @@ -644,28 +748,43 @@ public function traverse(string $file, string $input, string $output): int if ($newQueue->count()) { $reducedQueue->enqueue($newQueue); } elseif (!$reducedQueue->count()) { - $this->eventHandler?->onEndAstTraversal($input, 0); - return 0; + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onEndAstTraversal($input, 0); + $phabelReturn = 0; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } - try { - $ast = new RootNode($this->parser->parse(\file_get_contents($input)) ?? []); - } catch (\Throwable $e) { + $ast = new \Phabel\RootNode(null !== ($phabel_6f5fa46f697baa56 = $this->parser->parse(\file_get_contents($input))) ? $phabel_6f5fa46f697baa56 : []); + } catch (\Exception $e) { + $message = $e->getMessage(); + $message .= " while parsing "; + $message .= $input; + throw new \Phabel\Exception($message, (int) $e->getCode(), $e, $e->getFile(), $e->getLine()); + } catch (\Error $e) { $message = $e->getMessage(); $message .= " while parsing "; $message .= $input; - throw new Exception($message, (int) $e->getCode(), $e, $e->getFile(), $e->getLine()); + throw new \Phabel\Exception($message, (int) $e->getCode(), $e, $e->getFile(), $e->getLine()); } - $this->file = $file; $this->inputFile = $input; $this->outputFile = $output; - [$it, $result] = $this->traverseAstInternal($ast, $reducedQueue); + list($it, $result) = $this->traverseAstInternal($ast, $reducedQueue); \file_put_contents($output, $result); - - $this->eventHandler?->onEndAstTraversal($input, $it); - - return $it; + \Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->eventHandler) ? $this->eventHandler : \Phabel\Target\Php80\NullSafe\NullSafe::$singleton)->onEndAstTraversal($input, $it); + $phabelReturn = $it; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } /** * Traverse AST. @@ -678,13 +797,26 @@ public function traverse(string $file, string $input, string $output): int * * @return int */ - public function traverseAst(Node &$node, SplQueue $pluginQueue = null, bool $allowMulti = true): int + public function traverseAst(Node &$node, SplQueue $pluginQueue = null, $allowMulti = \true) { + if (!\is_bool($allowMulti)) { + if (!(\is_bool($allowMulti) || \is_numeric($allowMulti) || \is_string($allowMulti))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($allowMulti) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($allowMulti) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $allowMulti = (bool) $allowMulti; + } $this->file = ''; $this->inputFile = ''; $this->outputFile = ''; - $n = new RootNode([&$node]); - return $this->traverseAstInternal($n, $pluginQueue, $allowMulti)[0] ?? 0; + $n = new \Phabel\RootNode([&$node]); + $phabelReturn = null !== ($phabel_99db884988fa8271 = $this->traverseAstInternal($n, $pluginQueue, $allowMulti)) && isset($phabel_99db884988fa8271[0]) ? $phabel_99db884988fa8271[0] : 0; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (int) $phabelReturn; + } + return $phabelReturn; } /** * Traverse AST. @@ -701,15 +833,21 @@ public function traverseAst(Node &$node, SplQueue $pluginQueue = null, bool $all * @return array{0: int, 1: string}|null * @psalm-return (T is true ? array{0: int, 1: string} : null) */ - private function traverseAstInternal(RootNode &$node, SplQueue $pluginQueue = null, bool $allowMulti = true): ?array + private function traverseAstInternal(\Phabel\RootNode &$node, SplQueue $pluginQueue = null, $allowMulti = \true) { + if (!\is_bool($allowMulti)) { + if (!(\is_bool($allowMulti) || \is_numeric($allowMulti) || \is_string($allowMulti))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($allowMulti) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($allowMulti) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $allowMulti = (bool) $allowMulti; + } $it = 0; $result = $this->printer->prettyPrintFile($node->stmts); do { $context = null; try { - foreach ($pluginQueue ?? $this->packageQueue ?? $this->graph->getPlugins() as $queue) { - $context = new Context; + foreach (isset($pluginQueue) ? $pluginQueue : (isset($this->packageQueue) ? $this->packageQueue : $this->graph->getPlugins()) as $queue) { + $context = new \Phabel\Context(); $context->setFile($this->file); $context->setInputFile($this->inputFile); $context->setOutputFile($this->outputFile); @@ -718,25 +856,48 @@ private function traverseAstInternal(RootNode &$node, SplQueue $pluginQueue = nu /** @var RootNode $node */ } if (!$allowMulti) { - return null; + $phabelReturn = null; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + } catch (\Exception $e) { + $message = $e->getMessage(); + $message .= " while processing "; + $message .= $this->file; + $message .= ":"; + try { + $message .= $context ? $context->getCurrentChild($context->parents[0])->getStartLine() : "-1"; + } catch (\Exception $e) { + $message .= "-1"; + } catch (\Error $e) { + $message .= "-1"; } - } catch (\Throwable $e) { + throw new \Phabel\Exception($message, (int) $e->getCode(), $e, $e->getFile(), $e->getLine()); + } catch (\Error $e) { $message = $e->getMessage(); $message .= " while processing "; $message .= $this->file; $message .= ":"; try { $message .= $context ? $context->getCurrentChild($context->parents[0])->getStartLine() : "-1"; - } catch (\Throwable $e) { + } catch (\Exception $e) { + $message .= "-1"; + } catch (\Error $e) { $message .= "-1"; } - throw new Exception($message, (int) $e->getCode(), $e, $e->getFile(), $e->getLine()); + throw new \Phabel\Exception($message, (int) $e->getCode(), $e, $e->getFile(), $e->getLine()); } $oldResult = $result; $result = $this->printer->prettyPrintFile($node->stmts); $it++; } while ($result !== $oldResult); - return [$it, $result]; + $phabelReturn = [$it, $result]; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } /** * Traverse node. @@ -747,19 +908,19 @@ private function traverseAstInternal(RootNode &$node, SplQueue $pluginQueue = nu * * @return void */ - private function traverseNode(Node &$node, SplQueue $plugins, Context $context): void + private function traverseNode(Node &$node, SplQueue $plugins, \Phabel\Context $context) { $context->pushResolve($node); foreach ($plugins as $plugin) { - foreach (PluginCache::enterMethods(\get_class($plugin)) as $type => $methods) { - if (!$node instanceof $type) { + foreach (\Phabel\PluginCache::enterMethods(\get_class($plugin)) as $type => $methods) { + if (!\Phabel\Target\Php70\ThrowableReplacer::isInstanceofThrowable($node, $type)) { continue; } foreach ($methods as $method) { /** @var Node|null */ $result = $plugin->{$method}($node, $context); if ($result instanceof Node) { - if (!$result instanceof $node) { + if (!\Phabel\Target\Php70\ThrowableReplacer::isInstanceofThrowable($result, $node)) { $node = $result; continue 2; } @@ -772,9 +933,8 @@ private function traverseNode(Node &$node, SplQueue $plugins, Context $context): /** @var string $name */ foreach ($node->getSubNodeNames() as $name) { $node->setAttribute('currentNode', $name); - /** @var Node[]|Node|mixed */ - $subNode = &$node->{$name}; + $subNode =& $node->{$name}; if ($subNode instanceof Node) { $this->traverseNode($subNode, $plugins, $context); continue; @@ -797,15 +957,15 @@ private function traverseNode(Node &$node, SplQueue $plugins, Context $context): } $context->pop(); foreach ($plugins as $plugin) { - foreach (PluginCache::leaveMethods(\get_class($plugin)) as $type => $methods) { - if (!$node instanceof $type) { + foreach (\Phabel\PluginCache::leaveMethods(\get_class($plugin)) as $type => $methods) { + if (!\Phabel\Target\Php70\ThrowableReplacer::isInstanceofThrowable($node, $type)) { continue; } foreach ($methods as $method) { /** @var Node|null */ $result = $plugin->{$method}($node, $context); if ($result instanceof Node) { - if (!$result instanceof $node) { + if (!\Phabel\Target\Php70\ThrowableReplacer::isInstanceofThrowable($result, $node)) { $node = $result; continue 2; } @@ -815,10 +975,40 @@ private function traverseNode(Node &$node, SplQueue $plugins, Context $context): } } } - public function __destruct() { unset($this->graph); - while (\gc_collect_cycles()); + while (\gc_collect_cycles()) { + } + } +} +if (!\class_exists(\Phabel\PhabelAnonymousClass063d10f883fe83b0c12eba721edc03b9cc7383d4550ab4363c290322abe45bb50::class)) { + class PhabelAnonymousClass063d10f883fe83b0c12eba721edc03b9cc7383d4550ab4363c290322abe45bb50 implements \Phabel\Target\Php70\AnonymousClass\AnonymousClassInterface + { + private $coveragePath; + private $coverage; + public function __construct(CodeCoverage $coverage, $coveragePath) + { + if (!\is_string($coveragePath)) { + if (!(\is_string($coveragePath) || \is_object($coveragePath) && \method_exists($coveragePath, '__toString') || (\is_bool($coveragePath) || \is_numeric($coveragePath)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($coveragePath) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($coveragePath) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $coveragePath = (string) $coveragePath; + } + $this->coverage = $coverage; + $this->coveragePath = $coveragePath; + } + public function __destruct() + { + $this->coverage->stop(); + if (\file_exists($this->coveragePath)) { + $this->coverage->merge(require $this->coveragePath); + } + (new PHP())->process($this->coverage, $this->coveragePath); + } + public static function getPhabelOriginalName() + { + return 'class@anonymous'; + } } } diff --git a/src/VariableContext.php b/src/VariableContext.php index d3fc25669..d3370c9cb 100644 --- a/src/VariableContext.php +++ b/src/VariableContext.php @@ -15,7 +15,7 @@ class VariableContext * * @var array */ - private array $variables; + private $variables; /** * Constructor. * @@ -32,9 +32,15 @@ public function __construct(array $variables = []) * * @return void */ - public function addVar(string $var): void + public function addVar($var) { - $this->variables[$var] = true; + if (!\is_string($var)) { + if (!(\is_string($var) || \is_object($var) && \method_exists($var, '__toString') || (\is_bool($var) || \is_numeric($var)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($var) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($var) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $var = (string) $var; + } + $this->variables[$var] = \true; } /** * Add variables. @@ -43,7 +49,7 @@ public function addVar(string $var): void * * @return void */ - public function addVars(array $vars): void + public function addVars(array $vars) { $this->variables += $vars; } @@ -54,8 +60,14 @@ public function addVars(array $vars): void * * @return void */ - public function removeVar(string $var): void + public function removeVar($var) { + if (!\is_string($var)) { + if (!(\is_string($var) || \is_object($var) && \method_exists($var, '__toString') || (\is_bool($var) || \is_numeric($var)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($var) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($var) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $var = (string) $var; + } unset($this->variables[$var]); } /** @@ -64,30 +76,54 @@ public function removeVar(string $var): void * @param string $var * @return boolean */ - public function hasVar(string $var): bool + public function hasVar($var) { - return isset($this->variables[$var]); + if (!\is_string($var)) { + if (!(\is_string($var) || \is_object($var) && \method_exists($var, '__toString') || (\is_bool($var) || \is_numeric($var)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($var) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($var) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $var = (string) $var; + } + $phabelReturn = isset($this->variables[$var]); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (bool) $phabelReturn; + } + return $phabelReturn; } /** * Get unused variable name. * * @return string */ - public function getVar(): string + public function getVar() { do { - $var = 'phabel_'.\bin2hex(\random_bytes(8)); + $var = 'phabel_' . \bin2hex(\random_bytes(8)); } while (isset($this->variables[$var])); - $this->variables[$var] = true; - return $var; + $this->variables[$var] = \true; + $phabelReturn = $var; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } /** * Get all variables currently defined. * * @return array */ - public function getVars(): array + public function getVars() { - return $this->variables; + $phabelReturn = $this->variables; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; } } diff --git a/src/Version.php b/src/Version.php index cbb847117..0b7b39be5 100644 --- a/src/Version.php +++ b/src/Version.php @@ -10,16 +10,15 @@ class Version /** * Latest git tag. */ - public const VERSION = '^1.0'; + const VERSION = '^1.0'; /** * Latest revision. */ - public const LATEST = 0; + const LATEST = 0; /** * Changelog. */ - public const CHANGELOG = [ - 0 => 'Welcome! You can now use PHP 8 features in your code. + const CHANGELOG = [0 => 'Welcome! You can now use PHP 8 features in your code. Config recap: Source PHP version: 8.0 @@ -31,6 +30,5 @@ class Version See https://phabel.io for documentation and more configuration parameters. Have fun! -', - ]; +']; } diff --git a/src/phabel.php b/src/phabel.php index 24bbc3e1c..d204c3fc3 100644 --- a/src/phabel.php +++ b/src/phabel.php @@ -5,12 +5,10 @@ use Phabel\Cli\Formatter; use Phabel\Commands\Publish; use Phabel\Commands\Run; -use Symfony\Component\Console\Application; - +use Phabel\Symfony\Component\Console\Application; if (!\class_exists(Run::class)) { - require __DIR__.'/../vendor/autoload.php'; + require __DIR__ . '/../vendor/autoload.php'; } - $app = new Application(Formatter::banner()); $app->add(new Publish()); $app->add(new Run()); diff --git a/tools/ci/coverageMerge.php b/tools/ci/coverageMerge.php index 38d76f950..49abcda09 100644 --- a/tools/ci/coverageMerge.php +++ b/tools/ci/coverageMerge.php @@ -5,19 +5,17 @@ use SebastianBergmann\CodeCoverage\Report\Text; require 'vendor/autoload.php'; - $coverage = null; foreach (\glob("coverage/*.php") as $file) { - echo "Processing $file...".PHP_EOL; + echo "Processing {$file}..." . PHP_EOL; if (!$coverage) { - $coverage = include $file; + $coverage = (include $file); continue; } /** @var CodeCoverage $coverage */ $coverage->merge(include $file); } - if ($coverage) { - (new Clover)->process($coverage, 'coverage/clover.xml'); - echo (new Text(50, 90, true))->process($coverage, true).PHP_EOL; + (new Clover())->process($coverage, 'coverage/clover.xml'); + echo (new Text(50, 90, true))->process($coverage, true) . PHP_EOL; } diff --git a/tools/ci/functions.php b/tools/ci/functions.php index e6cbb5018..0c14734a6 100644 --- a/tools/ci/functions.php +++ b/tools/ci/functions.php @@ -6,8 +6,14 @@ * @param string $cmd * @return void */ -function r(string $cmd) +function r($cmd) { + if (!\is_string($cmd)) { + if (!(\is_string($cmd) || \is_object($cmd) && \method_exists($cmd, '__toString') || (\is_bool($cmd) || \is_numeric($cmd)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($cmd) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cmd) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $cmd = (string) $cmd; + } \passthru($cmd, $ret); if ($ret) { die($ret); diff --git a/tools/ci/matrix.php b/tools/ci/matrix.php index 46299a0df..926532db6 100644 --- a/tools/ci/matrix.php +++ b/tools/ci/matrix.php @@ -1,41 +1,31 @@ $os, - 'php' => $final, - 'shouldBuild' => [$doBuild ? 'yes' : 'no'], - 'shouldTag' => [$tag] -]; +$matrix = ['os' => $os, 'php' => $final, 'shouldBuild' => [$doBuild ? 'yes' : 'no'], 'shouldTag' => [$tag]]; $matrix = \json_encode($matrix); - -echo "::set-output name=matrix::$matrix".PHP_EOL; +echo "::set-output name=matrix::{$matrix}" . PHP_EOL; diff --git a/tools/ci/prepareDeps.php b/tools/ci/prepareDeps.php index 1e6ce05f6..91ce153c5 100644 --- a/tools/ci/prepareDeps.php +++ b/tools/ci/prepareDeps.php @@ -6,31 +6,21 @@ require 'vendor/autoload.php'; require 'functions.php'; - -$tail = $argv[1] ?? ''; +$tail = isset($argv[1]) ? $argv[1] : ''; foreach (Php::VERSIONS as $version) { - if ($tail === "-$version") { + if ($tail === "-{$version}") { break; } } - `rm -rf ../phabelConverted`; - -$packages = (new Traverser(EventHandler::create())) - ->setPlugins([Php::class => ['target' => $version]]) - ->setInput('vendor-bin/') - ->setOutput('../phabelConverted') - ->setCoverage('coverage/convertVendor.php') - ->run(\getenv('PHABEL_PARALLEL') ?: 1); - +$packages = (new Traverser(EventHandler::create()))->setPlugins([Php::class => ['target' => $version]])->setInput('vendor-bin/')->setOutput('../phabelConverted')->setCoverage('coverage/convertVendor.php')->run(\getenv('PHABEL_PARALLEL') ?: 1); `rm -rf vendor-bin/`; `mv ../phabelConverted/ vendor-bin/`; - if (!empty($packages)) { \chdir("vendor-bin/check"); - $cmd = "php $(which composer) require --dev --ignore-platform-reqs "; + $cmd = "php \$(which composer) require --dev --ignore-platform-reqs "; foreach ($packages as $package => $constraint) { - $cmd .= \escapeshellarg("{$package}:{$constraint}")." "; + $cmd .= \escapeshellarg("{$package}:{$constraint}") . " "; } r($cmd); } diff --git a/tools/convertPhabel.php b/tools/convertPhabel.php index 9e8632b0c..e8d9b2398 100644 --- a/tools/convertPhabel.php +++ b/tools/convertPhabel.php @@ -22,28 +22,30 @@ die(1); } $target = $argv[1]; -$dry = (bool) ($argv[2] ?? ''); +$dry = (bool) (isset($argv[2]) ? $argv[2] : ''); $branch = 'master'; $tag = \getenv('shouldTag') ?: null; - -$home = \realpath(__DIR__.'/../'); +$home = \realpath(__DIR__ . '/../'); r("rm -rf ../phabelConvertedInput"); \mkdir('../phabelConvertedInput'); - if (!$dry) { r("rm -rf ../phabelConvertedRepo"); - r("cp -a $home ../phabelConvertedRepo"); + r("cp -a {$home} ../phabelConvertedRepo"); r("rm -rf ../phabelConvertedRepo/vendor"); } - -function commit(string $message) +function commit($message) { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $message = (string) $message; + } r("cp -a ../phabelConvertedOutput/* ../phabelConvertedRepo"); \chdir("../phabelConvertedRepo/"); r("git add -A"); r("git commit -m " . \escapeshellarg($message)); } - foreach ($target === 'all' ? Php::VERSIONS : [$target] as $realTarget) { $realTarget = Php::normalizeVersion($realTarget); if (!$dry) { @@ -55,18 +57,11 @@ function commit(string $message) } r("rm -rf ../phabelConvertedOutput"); \mkdir('../phabelConvertedOutput'); - $coverage = \getenv('PHABEL_COVERAGE') ?: ''; if ($coverage) { $coverage .= "-{$realTarget}"; } - $packages = (new Traverser(EventHandler::create())) - ->setInput('../phabelConvertedOutput') - ->setOutput('../phabelConvertedOutput') - ->setPlugins([Php::class => ['target' => $realTarget]]) - ->setCoverage($coverage) - ->run((int) (\getenv('PHABEL_PARALLEL') ?: 1)); - + $packages = (new Traverser(EventHandler::create()))->setInput('../phabelConvertedOutput')->setOutput('../phabelConvertedOutput')->setPlugins([Php::class => ['target' => $realTarget]])->setCoverage($coverage)->run((int) (\getenv('PHABEL_PARALLEL') ?: 1)); \chdir($home); r("cp -a * .php-cs-fixer.dist.php ../phabelConvertedInput"); \chdir("../phabelConvertedInput"); @@ -77,14 +72,13 @@ function commit(string $message) if ($package === 'php') { continue; } - $cmd .= \escapeshellarg("{$package}:{$constraint}")." "; + $cmd .= \escapeshellarg("{$package}:{$constraint}") . " "; } r($cmd); } r("composer update --no-dev"); r("rm -rf tests testsGenerated"); - - foreach ([Php::VERSIONS[\count(Php::VERSIONS)-1], $realTarget] as $k => $target) { + foreach ([Php::VERSIONS[\count(Php::VERSIONS) - 1], $realTarget] as $k => $target) { if ($k === 0) { $input = "../phabelConvertedInput"; $output = "../phabelConvertedOutput"; @@ -92,21 +86,13 @@ function commit(string $message) $input = $output = "../phabelConvertedOutput"; } \chdir($input); - $coverage = \getenv('PHABEL_COVERAGE') ?: ''; if ($coverage) { $coverage .= "-{$target}"; } - (new Traverser(EventHandler::create())) - ->setInput($input) - ->setOutput($output) - ->setPlugins([Php::class => ['target' => $target]]) - ->setCoverage($coverage) - ->run((int) (\getenv('PHABEL_PARALLEL') ?: 1)); - + (new Traverser(EventHandler::create()))->setInput($input)->setOutput($output)->setPlugins([Php::class => ['target' => $target]])->setCoverage($coverage)->run((int) (\getenv('PHABEL_PARALLEL') ?: 1)); \chdir($output); - r("$home/vendor/bin/php-cs-fixer fix"); - + r("{$home}/vendor/bin/php-cs-fixer fix"); if (!$dry) { commit("phabel.io: transpile to {$target}"); } @@ -114,64 +100,53 @@ function commit(string $message) \chdir($home); r("cp -a testsGenerated tests ../phabelConvertedOutput"); \chdir("../phabelConvertedOutput"); - r("$home/vendor/bin/php-scoper add-prefix -c $home/scoper.inc.php"); + r("{$home}/vendor/bin/php-scoper add-prefix -c {$home}/scoper.inc.php"); r("rm -rf vendor"); r("cp -a build/. ."); r("rm -rf build vendor/composer vendor/autoload.php vendor/scoper-autoload.php vendor/bin"); \rename("vendor", "vendor-bundle"); r("find src -type f -exec sed 's/\\\\Phabel\\\\self/self/g' -i {} +"); - - \file_put_contents('vendor-bundle/autoload.php', << $packages['php'], - 'ext-json' => $json['require']['ext-json'], - 'composer-plugin-api' => $json['require']['composer-plugin-api'], - ]; - + $json['require'] = ['php' => $packages['php'], 'ext-json' => $json['require']['ext-json'], 'composer-plugin-api' => $json['require']['composer-plugin-api']]; foreach ($lock['packages'] as $package) { $name = $package['name']; - if ($name === 'phabel/phabel') { continue; } - - $json['require'] += \array_filter($package['require'], fn ($s) => \str_starts_with($s, 'ext-'), ARRAY_FILTER_USE_KEY); - + $json['require'] += \array_filter($package['require'], function ($s) { + return \str_starts_with($s, 'ext-'); + }, ARRAY_FILTER_USE_KEY); foreach (['psr-4', 'psr-0'] as $type) { - foreach ($package['autoload'][$type] ?? [] as $namespace => $path) { - $namespace = "Phabel\\$namespace"; + foreach (isset($package['autoload'][$type]) ? $package['autoload'][$type] : [] as $namespace => $path) { + $namespace = "Phabel\\{$namespace}"; $paths = \is_string($path) ? [$path] : $path; - $paths = \array_map(fn ($path) => "vendor-bundle/$name/$path", $paths); + $paths = \array_map(function ($path) use ($name) { + return "vendor-bundle/{$name}/{$path}"; + }, $paths); $json['autoload'][$type][$namespace] = $paths; } } - - $json['autoload']['files'] = \array_merge( - $json['autoload']['files'] ?? [], - \array_map( - fn ($path) => "vendor-bundle/$name/$path", - $package['autoload']['files'] ?? [] - ) - ); + $json['autoload']['files'] = \array_merge(isset($json['autoload']['files']) ? $json['autoload']['files'] : [], \array_map(function ($path) use ($name) { + return "vendor-bundle/{$name}/{$path}"; + }, isset($package['autoload']['files']) ? $package['autoload']['files'] : [])); } $json['autoload-dev'] = ['psr-4' => ['PhabelTest\\' => 'tests/']]; - - \file_put_contents('composer.json', \json_encode($json, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)); - + \file_put_contents('composer.json', \json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); if (!$dry) { commit("phabel.io: add dependencies"); \chdir("../phabelConvertedRepo"); if ($tag) { - r("git tag ".\escapeshellarg("$tag.$target")); - r("git push -f origin " . \escapeshellarg("$tag.$target")); + r("git tag " . \escapeshellarg("{$tag}.{$target}")); + r("git push -f origin " . \escapeshellarg("{$tag}.{$target}")); } r("git push -f origin " . \escapeshellarg("phabel_tmp:{$branch}-{$target}")); r("git checkout " . \escapeshellarg($branch)); diff --git a/tools/dump.php b/tools/dump.php index 445751fd9..552d4c548 100644 --- a/tools/dump.php +++ b/tools/dump.php @@ -1,23 +1,20 @@ * @license MIT */ - use PhpParser\ParserFactory; use PhpParser\PrettyPrinter\Standard; require 'vendor/autoload.php'; - if ($argc < 2) { - echo("Usage: {$argv[0]} file.php\n"); + echo "Usage: {$argv[0]} file.php\n"; die(1); } - -$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); +$parser = (new ParserFactory())->create(ParserFactory::PREFER_PHP7); //$parser = (new ParserFactory)->create(ParserFactory::ONLY_PHP5); - \var_dump($a = $parser->parse(\file_get_contents($argv[1]))); \var_dumP((new Standard())->prettyPrint($a)); diff --git a/tools/exprGen.php b/tools/exprGen.php index 67bc443d4..ebc45d4b8 100644 --- a/tools/exprGen.php +++ b/tools/exprGen.php @@ -1,4 +1,5 @@ * @license MIT */ - use HaydenPierce\ClassFinder\ClassFinder; use Phabel\Plugin\IssetExpressionFixer; use Phabel\Plugin\NestedExpressionFixer; @@ -54,26 +54,20 @@ use PhpParser\PrettyPrinter\Standard; require_once 'vendor/autoload.php'; - foreach (Php::VERSIONS as $version) { - if (empty(\shell_exec("which php$version 2>&1"))) { - echo("Could not find PHP $version!".PHP_EOL); + if (empty(\shell_exec("which php{$version} 2>&1"))) { + echo "Could not find PHP {$version}!" . PHP_EOL; die(1); } } - class ExpressionGenerator { - private Standard $printer; + private $printer; private function format(Node $code) { static $count = 0; $count++; - $code = (new Class_("lmao{$count}"))->addStmt( - (new Method("te")) - ->addStmt($code) - ->getNode() - )->getNode(); + $code = (new Class_("lmao{$count}"))->addStmt((new Method("te"))->addStmt($code)->getNode())->getNode(); return $this->printer->prettyPrintFile([$code]); } private function readUntilPrompt($resource) @@ -84,31 +78,51 @@ private function readUntilPrompt($resource) } return \substr($data, 0, -6); } - private array $robin = []; - private array $processes = []; - private array $pipes = []; - private function checkSyntaxVersion(int $version, string $code) + private $robin = []; + private $processes = []; + private $pipes = []; + private function checkSyntaxVersion($version, $code) { - $code = \str_replace(["\n", 'robin[$version]; $this->robin[$version]++; $this->robin[$version] %= \count($this->pipes[$version]); - \fputs($this->pipes[$version][$x][0], $code); - $result = $this->readUntilPrompt($this->pipes[$version][$x][1]); $result = \str_replace(['{', '}'], '', \substr(\preg_replace('#\\x1b[[][^A-Za-z]*[A-Za-z]#', '', $result), \strlen($code))); $result = \trim($result); //var_dump($code, "Result for $version is: $result"); return \strlen($result) === 0; } - private function checkSyntax(string $code, int $startFrom = 56) + private function checkSyntax($code, $startFrom = 56) { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $code = (string) $code; + } + if (!\is_int($startFrom)) { + if (!(\is_bool($startFrom) || \is_numeric($startFrom))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($startFrom) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($startFrom) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $startFrom = (int) $startFrom; + } if (!$startFrom) { return $startFrom; } - foreach (Php::VERSIONS as $version) { if ($version < $startFrom) { continue; @@ -119,57 +133,43 @@ private function checkSyntax(string $code, int $startFrom = 56) } return 0; } - private $result = [ - 'main' => [], // Needs adaptation for nested expressions - 'isset' => [], // Needs adaptation for nested expressions in isset + 'main' => [], + // Needs adaptation for nested expressions + 'isset' => [], ]; /** @psalm-var array> */ - private array $tests = []; + private $tests = []; private $versionMap = []; - - private function checkPossibleValue($arg, $name, $key, $class, $baseArgs, $isArray) { - $subVersion = \max($this->versionMap[\get_debug_type($arg)] ?? 0, $this->versionMap[$class]); - + $subVersion = \max(isset($this->versionMap[\get_debug_type($arg)]) ? $this->versionMap[\get_debug_type($arg)] : 0, $this->versionMap[$class]); $arguments = $baseArgs; $arguments[$key] = $isArray ? [$arg] : $arg; - $code = $this->format($prev = new $class(...$arguments)); $curVersion = $this->checkSyntax($code, $subVersion); if ($curVersion && $curVersion !== $subVersion) { $this->result['main'][$curVersion][$class][$name][\get_debug_type($arg)] = true; - echo "Min $curVersion for $code\n"; + echo "Min {$curVersion} for {$code}\n"; } - if ($curVersion - && !($class === AssignRef::class && $arg instanceof New_) - && !($class === Yield_::class && $name === 'key' && ($arg instanceof LogicalAnd || $arg instanceof LogicalOr || $arg instanceof LogicalXor)) - && !(\in_array($class, [MethodCall::class, StaticCall::class]) && $name === 'name' && ($arg instanceof Array_ || $arg instanceof Print_)) - && !(\in_array($class, [UnaryPlus::class, UnaryMinus::class, BitwiseNot::class]) && $arg instanceof Array_) - && !(\in_array($class, [Variable::class, StaticPropertyFetch::class, PropertyFetch::class]) && $arg instanceof Array_) - ) { + if ($curVersion && !($class === AssignRef::class && $arg instanceof New_) && !($class === Yield_::class && $name === 'key' && ($arg instanceof LogicalAnd || $arg instanceof LogicalOr || $arg instanceof LogicalXor)) && !(\in_array($class, [MethodCall::class, StaticCall::class]) && $name === 'name' && ($arg instanceof Array_ || $arg instanceof Print_)) && !(\in_array($class, [UnaryPlus::class, UnaryMinus::class, BitwiseNot::class]) && $arg instanceof Array_) && !(\in_array($class, [Variable::class, StaticPropertyFetch::class, PropertyFetch::class]) && $arg instanceof Array_)) { $this->tests[] = $prev; } - $code = $this->format(new Isset_([$prev])); $curVersion = $this->checkSyntax($code, $subVersion); if ($curVersion && $curVersion !== $subVersion) { $this->result['isset'][$curVersion][$class][$name][\get_debug_type($arg)] = true; - echo "Min $curVersion for $code\n"; + echo "Min {$curVersion} for {$code}\n"; } - if ($curVersion - && !(\in_array($class, [Variable::class, StaticPropertyFetch::class, PropertyFetch::class]) && $arg instanceof Array_) - ) { + if ($curVersion && !(\in_array($class, [Variable::class, StaticPropertyFetch::class, PropertyFetch::class]) && $arg instanceof Array_)) { $this->tests[] = new Isset_([$prev]); } } - public function run() { $this->printer = new Standard(['shortArraySyntax' => true]); foreach (Php::VERSIONS as $version) { - $cmd = "php$version -a 2>&1"; + $cmd = "php{$version} -a 2>&1"; $this->pipes[$version] = []; $this->processes[$version] = []; $this->robin[$version] = 0; @@ -182,38 +182,29 @@ public function run() $expressions = []; foreach (ClassFinder::getClassesInNamespace('PhpParser', ClassFinder::RECURSIVE_MODE) as $class) { $class = new ReflectionClass($class); - if ($class->isSubclassOf(Expr::class) && !$class->isAbstract() - && $class->getName() !== PrintableNewAnonClassNode::class - && $class->getName() !== ArrowFunction::class - && $class->getName() !== Error::class - && $class->getName() !== List_::class - && $class->getName() !== ArrayItem::class - && $class->getName() !== EncapsedStringPart::class - && $class->getName() !== Exit_::class - && $class->getName() !== Unset_::class) { - $expressions []= $class; + if ($class->isSubclassOf(Expr::class) && !$class->isAbstract() && $class->getName() !== PrintableNewAnonClassNode::class && $class->getName() !== ArrowFunction::class && $class->getName() !== Error::class && $class->getName() !== List_::class && $class->getName() !== ArrayItem::class && $class->getName() !== EncapsedStringPart::class && $class->getName() !== Exit_::class && $class->getName() !== Unset_::class) { + $expressions[] = $class; } } - $instanceArgs = []; $instanceArgNames = []; $instanceArgTypes = []; - $exprInstances = []; foreach ($expressions as $expr) { $class = $expr->getName(); $method = $expr->getMethod('__construct'); if ($method->getNumberOfParameters() === 1) { $exprInstances[$class] = $expr->newInstance(); - continue; // Is a magic constant or such + continue; + // Is a magic constant or such } - \preg_match_all('/@param (?\S+) +\$(?\S+)/', $method->getDocComment(), $matches); + \preg_match_all('/@param (?\\S+) +\\$(?\\S+)/', $method->getDocComment(), $matches); $types = \array_combine($matches['name'], $matches['type']); foreach ($types as &$type) { $type = \explode("|", $type); foreach ($type as $key => &$subtype) { if (\str_starts_with($subtype, 'Node')) { - $subtype = 'PhpParser\\'.$subtype; + $subtype = 'PhpParser\\' . $subtype; } elseif ($subtype === 'Error') { unset($type[$key]); } elseif ($subtype === 'Identifier') { @@ -247,7 +238,7 @@ public function run() $arguments[] = new Name('self'); break; case 'array': - if (\in_array('Expr[]', $types[$param->getName()] ?? [])) { + if (\in_array('Expr[]', isset($types[$param->getName()]) ? $types[$param->getName()] : [])) { $argTypes[$key] = [true, [Expr::class]]; $arguments[] = [new Variable('test')]; } else { @@ -277,8 +268,6 @@ public function run() $instanceArgTypes[$class] = $argTypes; } } - - $disallowedIssetExprs = []; foreach ($exprInstances as $expr) { if (!$this->checkSyntaxVersion(56, $this->format(new Isset_([$expr])))) { @@ -286,28 +275,28 @@ public function run() } } $disallowedIssetExprs = \var_export($disallowedIssetExprs, true); - $disallowedIssetExprs = <<< PHP + $disallowedIssetExprs = << $instance) { $this->versionMap[$class] = $this->checkSyntax($this->format($instance)) ?: 1000; } - $wait = []; foreach ($instanceArgTypes as $class => $argTypes) { $baseArgs = $instanceArgs[$class]; - foreach ($argTypes as $key => [$isArray, $types]) { + foreach ($argTypes as $key => $phabel_67053abfb89d9db2) { + $isArray = $phabel_67053abfb89d9db2[0]; + $types = $phabel_67053abfb89d9db2[1]; $name = $instanceArgNames[$class][$key]; $possibleValues = []; foreach ($types as $type) { @@ -346,7 +335,6 @@ abstract class DisallowedExpressions extends Plugin } } } - $keys = []; foreach ($this->result['main'] as $version) { $keys = \array_merge_recursive($keys, $version); @@ -356,18 +344,18 @@ abstract class DisallowedExpressions extends Plugin } foreach (Php::VERSIONS as $version) { foreach (['NestedExpressionFixer', 'IssetExpressionFixer'] as $name) { - $code = <<< PHP + $code = << $config) { $config = \var_export($config, true); - $code = <<< PHP + $code = << $config + fixer::class => {$config} ]; } } PHP; - \file_put_contents("src/Target/Php$version/$name.php", $code); + \file_put_contents("src/Target/Php{$version}/{$name}.php", $code); } } - - $comment = <<< PHP + $comment = << * @license MIT @@ -414,49 +401,22 @@ public static function next(array \$config): array \unlink($file); } $prettyPrinter = new PhpParser\PrettyPrinter\Standard(['shortArraySyntax' => true]); - foreach (\array_chunk($this->tests, 100) as $stmts) { - $i = \hash('sha256', $prettyPrinter->prettyPrintFile($stmts))."Test"; - + $i = \hash('sha256', $prettyPrinter->prettyPrintFile($stmts)) . "Test"; $sortedStmts = []; foreach ($stmts as $stmt) { - $method = 'test'.\hash('sha256', $prettyPrinter->prettyPrintFile([$stmt])); - $sortedStmts[$method] = (new Method($method)) - ->addStmt( - new MethodCall( - new Variable('this'), - 'assertTrue', - [new Arg(Tools::fromLiteral(true))] - ) - ) - ->addStmt( - new Expression(new ArrowFunction( - ['expr' => $stmt] - )) - ) - ->getNode(); + $method = 'test' . \hash('sha256', $prettyPrinter->prettyPrintFile([$stmt])); + $sortedStmts[$method] = (new Method($method))->addStmt(new MethodCall(new Variable('this'), 'assertTrue', [new Arg(Tools::fromLiteral(true))]))->addStmt(new Expression(new ArrowFunction(['expr' => $stmt])))->getNode(); } \ksort($sortedStmts); - - $class = (new Class_("Expression$i")) - ->extend("TestCase") - ->setDocComment($comment) - ->addStmts(\array_values($sortedStmts)) - ->getNode(); - - $class = (new Namespace_(PhabelTest\Target::class)) - ->addStmt(new Use_(\PHPUnit\Framework\TestCase::class, StmtUse_::TYPE_NORMAL)) - ->addStmt($class) - ->getNode(); - + $class = (new Class_("Expression{$i}"))->extend("TestCase")->setDocComment($comment)->addStmts(\array_values($sortedStmts))->getNode(); + $class = (new Namespace_(PhabelTest\Target::class))->addStmt(new Use_(\PHPUnit\Framework\TestCase::class, StmtUse_::TYPE_NORMAL))->addStmt($class)->getNode(); $class = $prettyPrinter->prettyPrintFile([$class]); - - if (\file_exists("testsGenerated/Target/Expression$i.php")) { - throw new \RuntimeException("Expression$i.php already exists!"); + if (\file_exists("testsGenerated/Target/Expression{$i}.php")) { + throw new \RuntimeException("Expression{$i}.php already exists!"); } - \file_put_contents("testsGenerated/Target/Expression$i.php", $class); + \file_put_contents("testsGenerated/Target/Expression{$i}.php", $class); } } } - -(new ExpressionGenerator)->run(); +(new ExpressionGenerator())->run(); diff --git a/tools/testExprGen.php b/tools/testExprGen.php index 7e2e950e3..909c0a58d 100644 --- a/tools/testExprGen.php +++ b/tools/testExprGen.php @@ -9,86 +9,57 @@ use Phabel\Traverser; use SebastianBergmann\CodeCoverage\Driver\Selector; use SebastianBergmann\CodeCoverage\Filter; - use function Amp\Parallel\Worker\pool; require_once 'vendor/autoload.php'; - $canCoverage = false; try { - $filter = new Filter; - $filter->includeDirectory(\realpath(__DIR__.'/../src')); - (new Selector)->forLineCoverage($filter); + $filter = new Filter(); + $filter->includeDirectory(\realpath(__DIR__ . '/../src')); + (new Selector())->forLineCoverage($filter); $canCoverage = true; -} catch (\Throwable $e) { +} catch (\Exception $e) { +} catch (\Error $e) { } - if ($canCoverage) { pool(new DefaultPool(\getenv('CI') ? 3 : \count(Php::VERSIONS) + 2)); } - $fs = new Filesystem(); - const BASE = \PhabelTest\Target\TypeHintReplacerTest::class; - $packages = []; $packagesSecondary = []; foreach (Php::VERSIONS as $version) { - $types = [ - 'callable', 'iterable', 'object', 'self', 'static', - 'int', 'float', 'array', 'string', 'bool', - \Generator::class, - \str_replace("Target", "Target$version", \PhabelTest\Target\TypeHintReplacerTest::class), - ]; + $types = ['callable', 'iterable', 'object', 'self', 'static', 'int', 'float', 'array', 'string', 'bool', \Generator::class, \str_replace("Target", "Target{$version}", \PhabelTest\Target\TypeHintReplacerTest::class)]; foreach (\glob("testsGenerated/Target/TypeHintReplacer*") as $test) { - \preg_match("~(TypeHintReplacer\d+Test)~", $test, $matches); - $types []= BASE; - $types []= $r = \str_replace("TypeHintReplacerTest", $matches[1], BASE); - $types []= \str_replace("Target", "Target$version", BASE); - $types []= \str_replace("Target", "Target$version", $r); + \preg_match("~(TypeHintReplacer\\d+Test)~", $test, $matches); + $types[] = BASE; + $types[] = $r = \str_replace("TypeHintReplacerTest", $matches[1], BASE); + $types[] = \str_replace("Target", "Target{$version}", BASE); + $types[] = \str_replace("Target", "Target{$version}", $r); } - $fs->remove("testsGenerated/Target$version"); - $fs->remove("testsGenerated/Target10$version"); - $packages += (new Traverser(EventHandler::create())) - ->setPlugins([ - PhabelTestGenerator::class => ['target' => $version], - TypeHintReplacer::class => ['union' => true, 'nullable' => true, 'return' => true, 'types' => $types] - ]) - ->setInput('testsGenerated/Target') - ->setOutput("testsGenerated/Target$version") - ->setCoverage("expr$version") - ->runAsync(); - $packagesSecondary += (new Traverser(EventHandler::create())) - ->setPlugins([ - PhabelTestGenerator::class => ['target' => 1000+$version] - ]) - ->setInput("testsGenerated/Target$version") - ->setOutput("testsGenerated/Target10$version") - ->setCoverage("expr10$version") - ->runAsync(); + $fs->remove("testsGenerated/Target{$version}"); + $fs->remove("testsGenerated/Target10{$version}"); + $packages += (new Traverser(EventHandler::create()))->setPlugins([PhabelTestGenerator::class => ['target' => $version], TypeHintReplacer::class => ['union' => true, 'nullable' => true, 'return' => true, 'types' => $types]])->setInput('testsGenerated/Target')->setOutput("testsGenerated/Target{$version}")->setCoverage("expr{$version}")->runAsync(); + $packagesSecondary += (new Traverser(EventHandler::create()))->setPlugins([PhabelTestGenerator::class => ['target' => 1000 + $version]])->setInput("testsGenerated/Target{$version}")->setOutput("testsGenerated/Target10{$version}")->setCoverage("expr10{$version}")->runAsync(); } - if (!empty($packages)) { $cmd = "composer require --dev "; foreach ($packages as $package => $constraint) { - $cmd .= \escapeshellarg("$package:$constraint")." "; + $cmd .= \escapeshellarg("{$package}:{$constraint}") . " "; } - echo("Running $cmd...".PHP_EOL); + echo "Running {$cmd}..." . PHP_EOL; \passthru($cmd); } - -$binary = PHP_SAPI === 'phpdbg' ? PHP_BINARY." -qrr" : PHP_BINARY; - -$current = (int) (PHP_MAJOR_VERSION.PHP_MINOR_VERSION); +$binary = PHP_SAPI === 'phpdbg' ? PHP_BINARY . " -qrr" : PHP_BINARY; +$current = (int) (PHP_MAJOR_VERSION . PHP_MINOR_VERSION); foreach (\glob("testsGenerated/*/*.php") as $i => $test) { $version = (int) \substr(\basename(\dirname($test)), 6); $version = $version ?: 80; if ($version > $current) { continue; } - echo $test.PHP_EOL; - - \passthru("$binary vendor/bin/phpunit -c phpunit-expr.xml $test --coverage-php=coverage/phpunitExpr$i.php", $ret); + echo $test . PHP_EOL; + \passthru("{$binary} vendor/bin/phpunit -c phpunit-expr.xml {$test} --coverage-php=coverage/phpunitExpr{$i}.php", $ret); if ($ret) { die($ret); } diff --git a/tools/testGen.php b/tools/testGen.php index a9c3a6f21..a9b2d681e 100644 --- a/tools/testGen.php +++ b/tools/testGen.php @@ -7,43 +7,24 @@ use Phabel\Traverser; require_once 'vendor/autoload.php'; - $fs = new Filesystem(); $fs->remove("coverage"); \mkdir("coverage"); - $packages = []; $packagesSecondary = []; foreach (Php::VERSIONS as $version) { - echo "$version\n"; - $fs->remove("tests/Target$version"); - $fs->remove("tests/Target10$version"); - $packages += (new Traverser(EventHandler::create())) - ->setPlugins([ - PhabelTestGenerator::class => ['target' => $version] - ]) - ->setInput('tests/Target') - ->setOutput("tests/Target$version") - ->setCoverage("test$version") - ->run(\getenv('PHABEL_PARALLEL') ?: -1); - - (new Traverser(EventHandler::create())) - ->setPlugins([ - PhabelTestGenerator::class => ['target' => 1000+$version] - ]) - ->setInput("tests/Target$version") - ->setOutput("tests/Target10$version") - ->setCoverage("test10$version") - ->run(\getenv('PHABEL_PARALLEL') ?: -1); + echo "{$version}\n"; + $fs->remove("tests/Target{$version}"); + $fs->remove("tests/Target10{$version}"); + $packages += (new Traverser(EventHandler::create()))->setPlugins([PhabelTestGenerator::class => ['target' => $version]])->setInput('tests/Target')->setOutput("tests/Target{$version}")->setCoverage("test{$version}")->run(\getenv('PHABEL_PARALLEL') ?: -1); + (new Traverser(EventHandler::create()))->setPlugins([PhabelTestGenerator::class => ['target' => 1000 + $version]])->setInput("tests/Target{$version}")->setOutput("tests/Target10{$version}")->setCoverage("test10{$version}")->run(\getenv('PHABEL_PARALLEL') ?: -1); } - unset($packages['php']); - if (!empty($packages)) { $cmd = "composer require --dev "; foreach ($packages as $package => $constraint) { - $cmd .= \escapeshellarg("$package:$constraint")." "; + $cmd .= \escapeshellarg("{$package}:{$constraint}") . " "; } - echo("Running $cmd...".PHP_EOL); + echo "Running {$cmd}..." . PHP_EOL; \passthru($cmd); } diff --git a/tools/typeHintGen.php b/tools/typeHintGen.php index f8e8d9aa7..07339b069 100644 --- a/tools/typeHintGen.php +++ b/tools/typeHintGen.php @@ -1,199 +1,203 @@ * @license MIT */ - if (PHP_MAJOR_VERSION < 8) { - echo("This generator can only run on PHP 8.0+".PHP_EOL); + echo "This generator can only run on PHP 8.0+" . PHP_EOL; die(1); } - const CLAZZ = "PhabelTest\\Target\\TypeHintReplacerTest"; - -function escapeRegex(string $in): string +function escapeRegex($in) { - return \var_export('~'.\str_replace(['\\', '(', ')', '$', '?', '|'], ['\\\\', '\\(', '\\)', '\\$', '\\?', '\\|'], $in).'~', true); + if (!\is_string($in)) { + if (!(\is_string($in) || \is_object($in) && \method_exists($in, '__toString') || (\is_bool($in) || \is_numeric($in)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($in) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($in) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $in = (string) $in; + } + $phabelReturn = \var_export('~' . \str_replace(['\\', '(', ')', '$', '?', '|'], ['\\\\', '\\(', '\\)', '\\$', '\\?', '\\|'], $in) . '~', true); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $phabelReturn = (string) $phabelReturn; + } + return $phabelReturn; } - -function getErrorMessage(string $scalarParam, string $scalar, string $scalarSane, $wrongVal, string $to): array +function getErrorMessage($scalarParam, $scalar, $scalarSane, $wrongVal, $to) { + if (!\is_string($scalarParam)) { + if (!(\is_string($scalarParam) || \is_object($scalarParam) && \method_exists($scalarParam, '__toString') || (\is_bool($scalarParam) || \is_numeric($scalarParam)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($scalarParam) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($scalarParam) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $scalarParam = (string) $scalarParam; + } + if (!\is_string($scalar)) { + if (!(\is_string($scalar) || \is_object($scalar) && \method_exists($scalar, '__toString') || (\is_bool($scalar) || \is_numeric($scalar)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($scalar) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($scalar) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $scalar = (string) $scalar; + } + if (!\is_string($scalarSane)) { + if (!(\is_string($scalarSane) || \is_object($scalarSane) && \method_exists($scalarSane, '__toString') || (\is_bool($scalarSane) || \is_numeric($scalarSane)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($scalarSane) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($scalarSane) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $scalarSane = (string) $scalarSane; + } + if (!\is_string($to)) { + if (!(\is_string($to) || \is_object($to) && \method_exists($to, '__toString') || (\is_bool($to) || \is_numeric($to)))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($to) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($to) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $to = (string) $to; + } try { - $f = eval("return new class { public function r() { return fn ($scalarParam \$data): $scalar => \$data; }};"); - $f->r()(eval("return $wrongVal;")); - } catch (\Throwable $e) { + $f = eval("return new class { public function r() { return fn ({$scalarParam} \$data): {$scalar} => \$data; }};"); + $phabel_5c41897c31d84027 = $f->r(); + $phabel_5c41897c31d84027(eval("return {$wrongVal};")); + } catch (\Exception $e) { $message = $e->getMessage(); $message = \str_replace("self", CLAZZ, $message); $message = \preg_replace(["/called in .*/", "/.*: /"], ".*", $message); - if (\preg_match_all("/must be of type (\S+)/", $message, $matches)) { + if (\preg_match_all("/must be of type (\\S+)/", $message, $matches)) { foreach ($matches[1] as $match) { $message = \str_replace($match, \str_replace("class@anonymous", CLAZZ, $match), $message); } } - - $closureMessage = \str_replace( - "$to class@anonymous::{closure}", - "$to ".CLAZZ."::PhabelTest\\Target\\{closure}", - $message - ); - $methodMessage = \str_replace( - "$to class@anonymous::{closure}", - "$to ".CLAZZ."::test$scalarSane", - $message - ); - $funcMessage = \str_replace( - "$to class@anonymous::{closure}", - "$to PhabelTest\\Target\\test$scalarSane", - $message - ); + $closureMessage = \str_replace("{$to} class@anonymous::{closure}", "{$to} " . CLAZZ . "::PhabelTest\\Target\\{closure}", $message); + $methodMessage = \str_replace("{$to} class@anonymous::{closure}", "{$to} " . CLAZZ . "::test{$scalarSane}", $message); + $funcMessage = \str_replace("{$to} class@anonymous::{closure}", "{$to} PhabelTest\\Target\\test{$scalarSane}", $message); + } catch (\Error $e) { + $message = $e->getMessage(); + $message = \str_replace("self", CLAZZ, $message); + $message = \preg_replace(["/called in .*/", "/.*: /"], ".*", $message); + if (\preg_match_all("/must be of type (\\S+)/", $message, $matches)) { + foreach ($matches[1] as $match) { + $message = \str_replace($match, \str_replace("class@anonymous", CLAZZ, $match), $message); + } + } + $closureMessage = \str_replace("{$to} class@anonymous::{closure}", "{$to} " . CLAZZ . "::PhabelTest\\Target\\{closure}", $message); + $methodMessage = \str_replace("{$to} class@anonymous::{closure}", "{$to} " . CLAZZ . "::test{$scalarSane}", $message); + $funcMessage = \str_replace("{$to} class@anonymous::{closure}", "{$to} PhabelTest\\Target\\test{$scalarSane}", $message); + } + $phabelReturn = [escapeRegex($closureMessage), escapeRegex($methodMessage), escapeRegex($funcMessage)]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); } - return [escapeRegex($closureMessage), escapeRegex($methodMessage), escapeRegex($funcMessage)]; + return $phabelReturn; } - -$SCALARS = [ - 'callable' => ['"is_null"', 'fn (): int => 0', '[$this, "noop"]','[self::class, "noop"]'], - 'array' => ["['lmao']", 'array()'], - 'bool' => ["true", "false", '0', '1', '"0"', '"1"', '""', '"aaaa"'], - 'iterable' => ["['lmao']", 'array()', '(fn (): \\Generator => yield)()'], - 'float' => ["123", "-1", "123.123", "1e3", "true", "false", "'123'", '"123.123"'], - 'object' => ["new class{}", '$this'], - 'string' => ["'lmao'", 'new class{public function __toString() { return "lmao"; }}', "123", "-1", "123.123", "1e3", "true", "false"], - 'self' => ['$this'], - 'int' => ["123", "-1", "123.0", "1e3", "true", "false", "'123'", "'123.0'"], - '\\'.CLAZZ => ['$this'], - '\\Generator' => ['(fn (): \\Generator => yield)()'], -]; - +$SCALARS = ['callable' => ['"is_null"', 'fn (): int => 0', '[$this, "noop"]', '[self::class, "noop"]'], 'array' => ["['lmao']", 'array()'], 'bool' => ["true", "false", '0', '1', '"0"', '"1"', '""', '"aaaa"'], 'iterable' => ["['lmao']", 'array()', '(fn (): \\Generator => yield)()'], 'float' => ["123", "-1", "123.123", "1e3", "true", "false", "'123'", '"123.123"'], 'object' => ["new class{}", '$this'], 'string' => ["'lmao'", 'new class{public function __toString() { return "lmao"; }}', "123", "-1", "123.123", "1e3", "true", "false"], 'self' => ['$this'], 'int' => ["123", "-1", "123.0", "1e3", "true", "false", "'123'", "'123.0'"], '\\' . CLAZZ => ['$this'], '\\Generator' => ['(fn (): \\Generator => yield)()']]; $count = \count($SCALARS); $k = 0; foreach ($SCALARS as $scalar => $val) { - $SCALARS["?$scalar"] = [ - ...$val, - 'null' - ]; + $SCALARS["?{$scalar}"] = \array_merge($val, ['null']); $k = ($k + 1) % $count; $nextScalar = \array_keys($SCALARS)[$k]; $nextVal = $SCALARS[$nextScalar]; - - $SCALARS["$scalar|$nextScalar"] = [ - ...$val, - ...$nextVal, - ]; + $SCALARS["{$scalar}|{$nextScalar}"] = \array_merge($val, $nextVal); } foreach (\glob("testsGenerated/Target/TypeHintReplacer*") as $file) { \unlink($file); } - $closures = []; $closuresRet = []; $classFuncs = ''; $funcs = ''; $k = 0; - $count = 0; foreach ($SCALARS as $scalar => $vals) { foreach ($vals as $val) { $self = \strpos($scalar, 'self') !== false; - $scalarSane = ($k++).\preg_replace("~[^A-Za-z]*~", "", $scalar); + $scalarSane = $k++ . \preg_replace("~[^A-Za-z]*~", "", $scalar); $wrongVal = \strpos($scalar, 'object') !== false ? 0 : 'new class{}'; if ($scalar === 'float|object' || $scalar === 'object|string') { $wrongVal = 'null'; } - - [$closureMessage, $methodMessage, $funcMessage] = getErrorMessage($scalar, $scalar, $scalarSane, $wrongVal, "to"); - - $closures []= "[fn ($scalar \$data): $scalar => \$data, $val, $wrongVal, $closureMessage]"; - $closures []= "[function ($scalar \$data): $scalar { return \$data; }, $val, $wrongVal, $closureMessage]"; - $closures []= "[[\$this, 'test$scalarSane'], $val, $wrongVal, $methodMessage]"; - $closures []= "[[self::class, 'test$scalarSane'], $val, $wrongVal, $methodMessage]"; + list($closureMessage, $methodMessage, $funcMessage) = getErrorMessage($scalar, $scalar, $scalarSane, $wrongVal, "to"); + $closures[] = "[fn ({$scalar} \$data): {$scalar} => \$data, {$val}, {$wrongVal}, {$closureMessage}]"; + $closures[] = "[function ({$scalar} \$data): {$scalar} { return \$data; }, {$val}, {$wrongVal}, {$closureMessage}]"; + $closures[] = "[[\$this, 'test{$scalarSane}'], {$val}, {$wrongVal}, {$methodMessage}]"; + $closures[] = "[[self::class, 'test{$scalarSane}'], {$val}, {$wrongVal}, {$methodMessage}]"; if (!$self) { - $closures []= "['PhabelTest\\Target\\test$scalarSane', $val, $wrongVal, $funcMessage]"; + $closures[] = "['PhabelTest\\Target\\test{$scalarSane}', {$val}, {$wrongVal}, {$funcMessage}]"; } - - $classFuncs .= "private static function test$scalarSane($scalar \$data): $scalar { return \$data; }\n"; + $classFuncs .= "private static function test{$scalarSane}({$scalar} \$data): {$scalar} { return \$data; }\n"; if (!$self) { - $funcs .= "function test$scalarSane($scalar \$data): $scalar { return \$data; }\n"; + $funcs .= "function test{$scalarSane}({$scalar} \$data): {$scalar} { return \$data; }\n"; } - - [$closureMessage, $methodMessage, $funcMessage] = getErrorMessage("", $scalar, "Ret$scalarSane", $wrongVal, "value of"); - - $closuresRet []= "[fn (\$data): $scalar => \$data, $val, $wrongVal, $closureMessage]"; - $closuresRet []= "[function (\$data): $scalar { return \$data; }, $val, $wrongVal, $closureMessage]"; - $closuresRet []= "[[\$this, 'testRet$scalarSane'], $val, $wrongVal, $methodMessage]"; - $closuresRet []= "[[self::class, 'testRet$scalarSane'], $val, $wrongVal, $methodMessage]"; + list($closureMessage, $methodMessage, $funcMessage) = getErrorMessage("", $scalar, "Ret{$scalarSane}", $wrongVal, "value of"); + $closuresRet[] = "[fn (\$data): {$scalar} => \$data, {$val}, {$wrongVal}, {$closureMessage}]"; + $closuresRet[] = "[function (\$data): {$scalar} { return \$data; }, {$val}, {$wrongVal}, {$closureMessage}]"; + $closuresRet[] = "[[\$this, 'testRet{$scalarSane}'], {$val}, {$wrongVal}, {$methodMessage}]"; + $closuresRet[] = "[[self::class, 'testRet{$scalarSane}'], {$val}, {$wrongVal}, {$methodMessage}]"; if (!$self) { - $closuresRet []= "['PhabelTest\\Target\\testRet$scalarSane', $val, $wrongVal, $funcMessage]"; + $closuresRet[] = "['PhabelTest\\Target\\testRet{$scalarSane}', {$val}, {$wrongVal}, {$funcMessage}]"; } - - $classFuncs .= "private static function testRet$scalarSane(\$data): $scalar { return \$data; }\n"; + $classFuncs .= "private static function testRet{$scalarSane}(\$data): {$scalar} { return \$data; }\n"; if (!$self) { - $funcs .= "function testRet$scalarSane(\$data): $scalar { return \$data; }\n"; + $funcs .= "function testRet{$scalarSane}(\$data): {$scalar} { return \$data; }\n"; } - if (!($count++ % 5)) { - $i = ($count-1) / 5; + $i = ($count - 1) / 5; $i .= "Test"; + $provider = "[\n" . \implode(",\n", $closures) . "];\n"; + $providerRet = "[\n" . \implode(",\n", $closuresRet) . "];\n"; + $template = << - * @license MIT - */ - class TypeHintReplacer$i extends TestCase - { - /** - * @dataProvider returnDataProvider - */ - public function testRet(callable \$c, \$data, \$wrongData, string \$exception) { - \$this->assertTrue(\$data == \$c(\$data)); - - \$this->expectExceptionMessageMatches(\$exception); - \$c(\$wrongData); - } - public function returnDataProvider(): array - { - return $providerRet; - } - /** - * @dataProvider paramDataProvider - */ - public function test(callable \$c, \$data, \$wrongData, string \$exception) { - \$this->assertTrue(\$data == \$c(\$data)); - - \$this->expectExceptionMessageMatches(\$exception); - \$c(\$wrongData); - } - public function paramDataProvider(): array - { - return $provider; - } - - public static function noop() {} - - $classFuncs - } - EOF; +use PHPUnit\\Framework\\TestCase; + +{$funcs} - $template = \str_replace("TypeHintReplacerTest", "TypeHintReplacer$i", $template); +/** + * @author Daniil Gentili + * @license MIT + */ +class TypeHintReplacer{$i} extends TestCase +{ + /** + * @dataProvider returnDataProvider + */ + public function testRet(callable \$c, \$data, \$wrongData, string \$exception) { + \$this->assertTrue(\$data == \$c(\$data)); + + \$this->expectExceptionMessageMatches(\$exception); + \$c(\$wrongData); + } + public function returnDataProvider(): array + { + return {$providerRet}; + } + /** + * @dataProvider paramDataProvider + */ + public function test(callable \$c, \$data, \$wrongData, string \$exception) { + \$this->assertTrue(\$data == \$c(\$data)); + + \$this->expectExceptionMessageMatches(\$exception); + \$c(\$wrongData); + } + public function paramDataProvider(): array + { + return {$provider}; + } + + public static function noop() {} + + {$classFuncs} +} +EOF; + $template = \str_replace("TypeHintReplacerTest", "TypeHintReplacer{$i}", $template); $classFuncs = ''; $funcs = ''; $closures = []; $closuresRet = []; - - \file_put_contents("testsGenerated/Target/TypeHintReplacer$i.php", $template); + \file_put_contents("testsGenerated/Target/TypeHintReplacer{$i}.php", $template); } } } diff --git a/vendor-bin/check/composer.json b/vendor-bin/check/composer.json index 5ca5792c7..b5f8e4f96 100644 --- a/vendor-bin/check/composer.json +++ b/vendor-bin/check/composer.json @@ -5,6 +5,7 @@ "humbug/php-scoper": "^0.15.0", "amphp/php-cs-fixer-config": "dev-master", "phpunit/phpunit": "^7|^8|^9", - "phpunit/php-code-coverage": "*" + "phpunit/php-code-coverage": "*", + "php": ">=8.0 <8.1" } -} \ No newline at end of file +} diff --git a/vendor-bundle/amphp/amp/lib/CallableMaker.php b/vendor-bundle/amphp/amp/lib/CallableMaker.php new file mode 100644 index 000000000..b2cc866ba --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/CallableMaker.php @@ -0,0 +1,119 @@ +getMethod($method); + } + $phabelReturn = self::$__reflectionMethods[$method]->getClosure($this); + if (!\is_callable($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Creates a callable from a protected or private static method that may be invoked by methods requiring a + * publicly invokable callback. + * + * @param string $method Static method name. + * + * @return callable + * + * @psalm-suppress MixedInferredReturnType + */ + private static function callableFromStaticMethod($method) + { + if (!\is_string($method)) { + if (!(\is_string($method) || \is_object($method) && \method_exists($method, '__toString') || (\is_bool($method) || \is_numeric($method)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($method) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($method) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $method = (string) $method; + } + } + if (!isset(self::$__reflectionMethods[$method])) { + if (self::$__reflectionClass === null) { + self::$__reflectionClass = new \ReflectionClass(self::class); + } + self::$__reflectionMethods[$method] = self::$__reflectionClass->getMethod($method); + } + $phabelReturn = self::$__reflectionMethods[$method]->getClosure(); + if (!\is_callable($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + } +} else { + /** @psalm-suppress DuplicateClass */ + trait CallableMaker + { + /** + * @deprecated Use \Closure::fromCallable() instead of this method in PHP 7.1. + */ + private function callableFromInstanceMethod($method) + { + if (!\is_string($method)) { + if (!(\is_string($method) || \is_object($method) && \method_exists($method, '__toString') || (\is_bool($method) || \is_numeric($method)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($method) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($method) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $method = (string) $method; + } + } + $phabelReturn = \Phabel\Target\Php71\ClosureFromCallable::fromCallable([$this, $method]); + if (!\is_callable($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @deprecated Use \Closure::fromCallable() instead of this method in PHP 7.1. + */ + private static function callableFromStaticMethod($method) + { + if (!\is_string($method)) { + if (!(\is_string($method) || \is_object($method) && \method_exists($method, '__toString') || (\is_bool($method) || \is_numeric($method)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($method) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($method) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $method = (string) $method; + } + } + $phabelReturn = \Phabel\Target\Php71\ClosureFromCallable::fromCallable([self::class, $method]); + if (!\is_callable($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + } +} +// @codeCoverageIgnoreEnd diff --git a/vendor-bundle/amphp/amp/lib/CancellationToken.php b/vendor-bundle/amphp/amp/lib/CancellationToken.php new file mode 100644 index 000000000..2a4c88e0b --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/CancellationToken.php @@ -0,0 +1,46 @@ +getToken(); + * + * $response = yield $httpClient->request("https://example.com/stream", $token); + * $responseBody = $response->getBody(); + * + * while (($chunk = yield $response->read()) !== null) { + * // consume $chunk + * + * if ($noLongerInterested) { + * $cancellationTokenSource->cancel(); + * break; + * } + * } + * ``` + * + * @see CancellationToken + * @see CancelledException + */ +final class CancellationTokenSource +{ + /** @var CancellationToken */ + private $token; + /** @var callable|null */ + private $onCancel; + public function __construct() + { + $onCancel = null; + $this->token = new PhabelAnonymousClass867203916b829f7de24ce3f00173dbbad106acb640e8804052daf7588402a3bd2($onCancel); + $this->onCancel = $onCancel; + } + public function getToken() + { + $phabelReturn = $this->token; + if (!$phabelReturn instanceof CancellationToken) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type CancellationToken, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param \Throwable|null $previous Exception to be used as the previous exception to CancelledException. + * + * @return void + */ + public function cancel(\Throwable $previous = null) + { + if ($this->onCancel === null) { + return; + } + $onCancel = $this->onCancel; + $this->onCancel = null; + $onCancel(new CancelledException($previous)); + } +} +if (!\class_exists(PhabelAnonymousClass867203916b829f7de24ce3f00173dbbad106acb640e8804052daf7588402a3bd2::class)) { + class PhabelAnonymousClass867203916b829f7de24ce3f00173dbbad106acb640e8804052daf7588402a3bd2 implements CancellationToken, \Phabel\Target\Php70\AnonymousClass\AnonymousClassInterface + { + /** @var string */ + private $nextId = "a"; + /** @var callable[] */ + private $callbacks = []; + /** @var \Throwable|null */ + private $exception; + /** + * @param mixed $onCancel + * @param-out callable $onCancel + */ + public function __construct(&$onCancel) + { + /** @psalm-suppress MissingClosureReturnType We still support PHP 7.0 */ + $onCancel = function (\Throwable $exception) { + $this->exception = $exception; + $callbacks = $this->callbacks; + $this->callbacks = []; + foreach ($callbacks as $callback) { + $this->invokeCallback($callback); + } + }; + } + /** + * @param callable $callback + * + * @return void + */ + private function invokeCallback(callable $callback) + { + // No type declaration to prevent exception outside the try! + try { + /** @var mixed $result */ + $result = $callback($this->exception); + if ($result instanceof \Generator) { + /** @psalm-var \Generator $result */ + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + Loop::defer(static function () use($exception) { + throw $exception; + }); + } catch (\Error $exception) { + Loop::defer(static function () use($exception) { + throw $exception; + }); + } + } + public function subscribe(callable $callback) + { + $id = $this->nextId++; + if ($this->exception) { + $this->invokeCallback($callback); + } else { + $this->callbacks[$id] = $callback; + } + $phabelReturn = $id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(CancellationToken::class . '@anonymous:' . __FUNCTION__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function unsubscribe($id) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(CancellationToken::class . '@anonymous:' . __FUNCTION__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + unset($this->callbacks[$id]); + } + public function isRequested() + { + $phabelReturn = isset($this->exception); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(CancellationToken::class . '@anonymous:' . __FUNCTION__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function throwIfRequested() + { + if (isset($this->exception)) { + throw $this->exception; + } + } + public static function getPhabelOriginalName() + { + return CancellationToken::class . '@anonymous'; + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/CancelledException.php b/vendor-bundle/amphp/amp/lib/CancelledException.php new file mode 100644 index 000000000..1c48f70e5 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/CancelledException.php @@ -0,0 +1,17 @@ +subscribe(function (CancelledException $exception) { + $this->exception = $exception; + $callbacks = $this->callbacks; + $this->callbacks = []; + foreach ($callbacks as $callback) { + asyncCall($callback, $this->exception); + } + }); + $this->tokens[] = [$token, $id]; + } + } + public function __destruct() + { + foreach ($this->tokens as $phabel_750c92520065307d) { + $token = $phabel_750c92520065307d[0]; + $id = $phabel_750c92520065307d[1]; + /** @var CancellationToken $token */ + $token->unsubscribe($id); + } + } + /** @inheritdoc */ + public function subscribe(callable $callback) + { + $id = $this->nextId++; + if ($this->exception) { + asyncCall($callback, $this->exception); + } else { + $this->callbacks[$id] = $callback; + } + $phabelReturn = $id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** @inheritdoc */ + public function unsubscribe($id) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + unset($this->callbacks[$id]); + } + /** @inheritdoc */ + public function isRequested() + { + foreach ($this->tokens as $phabel_a3f69c8033d4887a) { + $token = $phabel_a3f69c8033d4887a[0]; + if ($token->isRequested()) { + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + } + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** @inheritdoc */ + public function throwIfRequested() + { + foreach ($this->tokens as $phabel_38ace34f4710eb6f) { + $token = $phabel_38ace34f4710eb6f[0]; + $token->throwIfRequested(); + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/Coroutine.php b/vendor-bundle/amphp/amp/lib/Coroutine.php new file mode 100644 index 000000000..63b0431cf --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Coroutine.php @@ -0,0 +1,160 @@ + + */ +final class Coroutine implements Promise +{ + use Internal\Placeholder; + /** + * Attempts to transform the non-promise yielded from the generator into a promise, otherwise returns an instance + * `Amp\Failure` failed with an instance of `Amp\InvalidYieldError`. + * + * @param mixed $yielded Non-promise yielded from generator. + * @param \Generator $generator No type for performance, we already know the type. + * + * @return Promise + */ + private static function transform($yielded, $generator) + { + $exception = null; + // initialize here, see https://github.com/vimeo/psalm/issues/2951 + try { + if (\is_array($yielded)) { + $phabelReturn = Promise\all($yielded); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($yielded instanceof ReactPromise) { + $phabelReturn = Promise\adapt($yielded); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + // No match, continue to returning Failure below. + } catch (\Exception $exception) { + // Conversion to promise failed, fall-through to returning Failure below. + } catch (\Error $exception) { + // Conversion to promise failed, fall-through to returning Failure below. + } + $phabelReturn = new Failure(new InvalidYieldError($generator, \sprintf("Unexpected yield; Expected an instance of %s or %s or an array of such instances", Promise::class, ReactPromise::class), $exception)); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param \Generator $generator + * @psalm-param \Generator,mixed,Promise|ReactPromise|TReturn> $generator + */ + public function __construct(\Generator $generator) + { + try { + $yielded = $generator->current(); + if (!$yielded instanceof Promise) { + if (!$generator->valid()) { + $this->resolve($generator->getReturn()); + return; + } + $yielded = self::transform($yielded, $generator); + } + } catch (\Exception $exception) { + $this->fail($exception); + return; + } catch (\Error $exception) { + $this->fail($exception); + return; + } + /** + * @param \Throwable|null $e Exception to be thrown into the generator. + * @param mixed $v Value to be sent into the generator. + * + * @return void + * + * @psalm-suppress MissingClosureParamType + * @psalm-suppress MissingClosureReturnType + */ + $onResolve = function (\Throwable $e = null, $v) use($generator, &$onResolve) { + /** @var bool $immediate Used to control iterative coroutine continuation. */ + static $immediate = \true; + /** @var \Throwable|null $exception Promise failure reason when executing next coroutine step, null at all other times. */ + static $exception; + /** @var mixed $value Promise success value when executing next coroutine step, null at all other times. */ + static $value; + $exception = $e; + /** @psalm-suppress MixedAssignment */ + $value = $v; + if (!$immediate) { + $immediate = \true; + return; + } + try { + try { + do { + if ($exception) { + // Throw exception at current execution point. + $yielded = $generator->throw($exception); + } else { + // Send the new value and execute to next yield statement. + $yielded = $generator->send($value); + } + if (!$yielded instanceof Promise) { + if (!$generator->valid()) { + $this->resolve($generator->getReturn()); + $onResolve = null; + return; + } + $yielded = self::transform($yielded, $generator); + } + $immediate = \false; + $yielded->onResolve($onResolve); + } while ($immediate); + $immediate = \true; + } catch (\Exception $exception) { + $this->fail($exception); + $onResolve = null; + } catch (\Error $exception) { + $this->fail($exception); + $onResolve = null; + } finally { + $exception = null; + $value = null; + } + } catch (\Exception $e) { + Loop::defer(static function () use($e) { + throw $e; + }); + } catch (\Error $e) { + Loop::defer(static function () use($e) { + throw $e; + }); + } + }; + try { + $yielded->onResolve($onResolve); + unset($generator, $yielded, $onResolve); + } catch (\Exception $e) { + Loop::defer(static function () use($e) { + throw $e; + }); + } catch (\Error $e) { + Loop::defer(static function () use($e) { + throw $e; + }); + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/Deferred.php b/vendor-bundle/amphp/amp/lib/Deferred.php new file mode 100644 index 000000000..cf7407e2f --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Deferred.php @@ -0,0 +1,89 @@ + Has public resolve and fail methods. */ + private $resolver; + /** @var Promise Hides placeholder methods */ + private $promise; + public function __construct() + { + $this->resolver = new PhabelAnonymousClass78674b341fc8ce1a3a6d684af60fb5c39331bf7c50114a496f0a39e563cb3d833(); + $this->promise = new Internal\PrivatePromise($this->resolver); + } + /** + * @return Promise + */ + public function promise() + { + $phabelReturn = $this->promise; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Fulfill the promise with the given value. + * + * @param mixed $value + * + * @psalm-param TValue|Promise $value + * + * @return void + */ + public function resolve($value = null) + { + /** @psalm-suppress UndefinedInterfaceMethod */ + $this->resolver->resolve($value); + } + /** + * Fails the promise the the given reason. + * + * @param \Throwable $reason + * + * @return void + */ + public function fail(\Throwable $reason) + { + /** @psalm-suppress UndefinedInterfaceMethod */ + $this->resolver->fail($reason); + } + /** + * @return bool True if the promise has been resolved. + */ + public function isResolved() + { + $phabelReturn = $this->resolver->isResolved(); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\class_exists(PhabelAnonymousClass78674b341fc8ce1a3a6d684af60fb5c39331bf7c50114a496f0a39e563cb3d833::class)) { + class PhabelAnonymousClass78674b341fc8ce1a3a6d684af60fb5c39331bf7c50114a496f0a39e563cb3d833 implements Promise, \Phabel\Target\Php70\AnonymousClass\AnonymousClassInterface + { + use Internal\Placeholder { + resolve as public; + fail as public; + isResolved as public; + } + public static function getPhabelOriginalName() + { + return Promise::class . '@anonymous'; + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/Delayed.php b/vendor-bundle/amphp/amp/lib/Delayed.php new file mode 100644 index 000000000..93f2fa167 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Delayed.php @@ -0,0 +1,67 @@ + + */ +final class Delayed implements Promise +{ + use Internal\Placeholder; + /** @var string|null Event loop watcher identifier. */ + private $watcher; + /** + * @param int $time Milliseconds before succeeding the promise. + * @param TReturn $value Succeed the promise with this value. + */ + public function __construct($time, $value = null) + { + if (!\is_int($time)) { + if (!(\is_bool($time) || \is_numeric($time))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($time) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($time) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $time = (int) $time; + } + } + $this->watcher = Loop::delay($time, function () use($value) { + $this->watcher = null; + $this->resolve($value); + }); + } + /** + * References the internal watcher in the event loop, keeping the loop running while this promise is pending. + * + * @return self + */ + public function reference() + { + if ($this->watcher !== null) { + Loop::reference($this->watcher); + } + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Unreferences the internal watcher in the event loop, allowing the loop to stop while this promise is pending if + * no other events are pending in the loop. + * + * @return self + */ + public function unreference() + { + if ($this->watcher !== null) { + Loop::unreference($this->watcher); + } + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/amp/lib/Emitter.php b/vendor-bundle/amphp/amp/lib/Emitter.php new file mode 100644 index 000000000..e4c5db560 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Emitter.php @@ -0,0 +1,93 @@ + Has public emit, complete, and fail methods. */ + private $emitter; + /** @var Iterator Hides producer methods. */ + private $iterator; + public function __construct() + { + $this->emitter = new PhabelAnonymousClassa53edb6f53fd8f3c2c413cbfc1be5e5edab46efe1086ce21f4f026e485307bc71(); + $this->iterator = new Internal\PrivateIterator($this->emitter); + } + /** + * @return Iterator + * @psalm-return Iterator + */ + public function iterate() + { + $phabelReturn = $this->iterator; + if (!$phabelReturn instanceof Iterator) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Iterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Emits a value to the iterator. + * + * @param mixed $value + * + * @psalm-param TValue $value + * + * @return Promise + * @psalm-return Promise + * @psalm-suppress MixedInferredReturnType + * @psalm-suppress MixedReturnStatement + */ + public function emit($value) + { + $phabelReturn = $this->emitter->emit($value); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** @psalm-suppress UndefinedInterfaceMethod */ + return $phabelReturn; + } + /** + * Completes the iterator. + * + * @return void + */ + public function complete() + { + /** @psalm-suppress UndefinedInterfaceMethod */ + $this->emitter->complete(); + } + /** + * Fails the iterator with the given reason. + * + * @param \Throwable $reason + * + * @return void + */ + public function fail(\Throwable $reason) + { + /** @psalm-suppress UndefinedInterfaceMethod */ + $this->emitter->fail($reason); + } +} +if (!\class_exists(PhabelAnonymousClassa53edb6f53fd8f3c2c413cbfc1be5e5edab46efe1086ce21f4f026e485307bc71::class)) { + class PhabelAnonymousClassa53edb6f53fd8f3c2c413cbfc1be5e5edab46efe1086ce21f4f026e485307bc71 implements Iterator, \Phabel\Target\Php70\AnonymousClass\AnonymousClassInterface + { + use Internal\Producer { + emit as public; + complete as public; + fail as public; + } + public static function getPhabelOriginalName() + { + return Iterator::class . '@anonymous'; + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/Failure.php b/vendor-bundle/amphp/amp/lib/Failure.php new file mode 100644 index 000000000..54e3927e3 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Failure.php @@ -0,0 +1,50 @@ + + */ +final class Failure implements Promise +{ + /** @var \Throwable $exception */ + private $exception; + /** + * @param \Throwable $exception Rejection reason. + */ + public function __construct(\Throwable $exception) + { + $this->exception = $exception; + } + /** + * {@inheritdoc} + */ + public function onResolve(callable $onResolved) + { + try { + /** @var mixed $result */ + $result = $onResolved($this->exception, null); + if ($result === null) { + return; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + Promise\rethrow($result); + } + } catch (\Exception $exception) { + Loop::defer(static function () use($exception) { + throw $exception; + }); + } catch (\Error $exception) { + Loop::defer(static function () use($exception) { + throw $exception; + }); + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/Internal/Placeholder.php b/vendor-bundle/amphp/amp/lib/Internal/Placeholder.php new file mode 100644 index 000000000..5b50c2286 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Internal/Placeholder.php @@ -0,0 +1,180 @@ +, mixed, + * mixed>|null)|callable(\Throwable|null, mixed): void */ + private $onResolved; + /** @var null|array */ + private $resolutionTrace; + /** + * @inheritdoc + */ + public function onResolve(callable $onResolved) + { + if ($this->resolved) { + if ($this->result instanceof Promise) { + $this->result->onResolve($onResolved); + return; + } + try { + /** @var mixed $result */ + $result = $onResolved(null, $this->result); + if ($result === null) { + return; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + Promise\rethrow($result); + } + } catch (\Exception $exception) { + Loop::defer(static function () use($exception) { + throw $exception; + }); + } catch (\Error $exception) { + Loop::defer(static function () use($exception) { + throw $exception; + }); + } + return; + } + if (null === $this->onResolved) { + $this->onResolved = $onResolved; + return; + } + if (!$this->onResolved instanceof ResolutionQueue) { + /** @psalm-suppress InternalClass */ + $this->onResolved = new ResolutionQueue($this->onResolved); + } + /** @psalm-suppress InternalMethod */ + $this->onResolved->push($onResolved); + } + public function __destruct() + { + try { + $this->result = null; + } catch (\Exception $e) { + Loop::defer(static function () use($e) { + throw $e; + }); + } catch (\Error $e) { + Loop::defer(static function () use($e) { + throw $e; + }); + } + } + /** + * @param mixed $value + * + * @return void + * + * @throws \Error Thrown if the promise has already been resolved. + */ + private function resolve($value = null) + { + if ($this->resolved) { + $message = "Promise has already been resolved"; + if (isset($this->resolutionTrace)) { + $trace = formatStacktrace($this->resolutionTrace); + $message .= ". Previous resolution trace:\n\n{$trace}\n\n"; + } else { + // @codeCoverageIgnoreStart + $message .= ', define environment variable AMP_DEBUG or const AMP_DEBUG = true and enable assertions for a stacktrace of the previous resolution.'; + // @codeCoverageIgnoreEnd + } + throw new \Error($message); + } + $phabel_b05875b884917dae = function () { + $env = \getenv("AMP_DEBUG") ?: "0"; + if ($env !== "0" && $env !== "false" || \defined("AMP_DEBUG") && \AMP_DEBUG) { + $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); + \array_shift($trace); + // remove current closure + $this->resolutionTrace = $trace; + } + return \true; + }; + \assert($phabel_b05875b884917dae()); + if ($value instanceof ReactPromise) { + $value = Promise\adapt($value); + } + $this->resolved = \true; + $this->result = $value; + if ($this->onResolved === null) { + return; + } + $onResolved = $this->onResolved; + $this->onResolved = null; + if ($this->result instanceof Promise) { + $this->result->onResolve($onResolved); + return; + } + try { + /** @var mixed $result */ + $result = $onResolved(null, $this->result); + $onResolved = null; + // allow garbage collection of $onResolved, to catch any exceptions from destructors + if ($result === null) { + return; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + Promise\rethrow($result); + } + } catch (\Exception $exception) { + Loop::defer(static function () use($exception) { + throw $exception; + }); + } catch (\Error $exception) { + Loop::defer(static function () use($exception) { + throw $exception; + }); + } + } + /** + * @param \Throwable $reason Failure reason. + * + * @return void + */ + private function fail(\Throwable $reason) + { + $this->resolve(new Failure($reason)); + } + /** + * @return bool True if the placeholder has been resolved. + */ + private function isResolved() + { + $phabelReturn = $this->resolved; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/amp/lib/Internal/PrivateIterator.php b/vendor-bundle/amphp/amp/lib/Internal/PrivateIterator.php new file mode 100644 index 000000000..9932452d7 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Internal/PrivateIterator.php @@ -0,0 +1,45 @@ + + */ +final class PrivateIterator implements Iterator +{ + /** @var Iterator */ + private $iterator; + /** + * @param Iterator $iterator + * + * @psalm-param Iterator $iterator + */ + public function __construct(Iterator $iterator) + { + $this->iterator = $iterator; + } + /** + * @return Promise + */ + public function advance() + { + $phabelReturn = $this->iterator->advance(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @psalm-return TValue + */ + public function getCurrent() + { + return $this->iterator->getCurrent(); + } +} diff --git a/vendor-bundle/amphp/amp/lib/Internal/PrivatePromise.php b/vendor-bundle/amphp/amp/lib/Internal/PrivatePromise.php new file mode 100644 index 000000000..beeaa14f9 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Internal/PrivatePromise.php @@ -0,0 +1,22 @@ +promise = $promise; + } + public function onResolve(callable $onResolved) + { + $this->promise->onResolve($onResolved); + } +} diff --git a/vendor-bundle/amphp/amp/lib/Internal/Producer.php b/vendor-bundle/amphp/amp/lib/Internal/Producer.php new file mode 100644 index 000000000..094af9fb4 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Internal/Producer.php @@ -0,0 +1,198 @@ + + */ + public function advance() + { + if ($this->waiting !== null) { + throw new \Error("The prior promise returned must resolve before invoking this method again"); + } + unset($this->values[$this->consumePosition]); + $position = ++$this->consumePosition; + if (\array_key_exists($position, $this->values)) { + \assert(isset($this->backPressure[$position])); + $deferred = $this->backPressure[$position]; + unset($this->backPressure[$position]); + $deferred->resolve(); + $phabelReturn = new Success(\true); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->complete) { + $phabelReturn = $this->complete; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $this->waiting = new Deferred(); + $phabelReturn = $this->waiting->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + * + * @return TValue + */ + public function getCurrent() + { + if (empty($this->values) && $this->complete) { + throw new \Error("The iterator has completed"); + } + if (!\array_key_exists($this->consumePosition, $this->values)) { + throw new \Error("Promise returned from advance() must resolve before calling this method"); + } + return $this->values[$this->consumePosition]; + } + /** + * Emits a value from the iterator. The returned promise is resolved once the emitted value has been consumed. + * + * @param mixed $value + * + * @return Promise + * @psalm-return Promise + * + * @throws \Error If the iterator has completed. + */ + private function emit($value) + { + if ($this->complete) { + throw new \Error("Iterators cannot emit values after calling complete"); + } + if ($value instanceof ReactPromise) { + $value = Promise\adapt($value); + } + if ($value instanceof Promise) { + $deferred = new Deferred(); + $value->onResolve(function ($e, $v) use($deferred) { + if ($this->complete) { + $deferred->fail(new \Error("The iterator was completed before the promise result could be emitted")); + return; + } + if ($e) { + $this->fail($e); + $deferred->fail($e); + return; + } + $deferred->resolve($this->emit($v)); + }); + $phabelReturn = $deferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $position = ++$this->emitPosition; + $this->values[$position] = $value; + if ($this->waiting !== null) { + $waiting = $this->waiting; + $this->waiting = null; + $waiting->resolve(\true); + $phabelReturn = new Success(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + // Consumer was already waiting for a new value, so back-pressure is unnecessary. + } + $this->backPressure[$position] = $pressure = new Deferred(); + $phabelReturn = $pressure->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Completes the iterator. + * + * @return void + * + * @throws \Error If the iterator has already been completed. + */ + private function complete() + { + if ($this->complete) { + $message = "Iterator has already been completed"; + if (isset($this->resolutionTrace)) { + $trace = formatStacktrace($this->resolutionTrace); + $message .= ". Previous completion trace:\n\n{$trace}\n\n"; + } else { + // @codeCoverageIgnoreStart + $message .= ', define environment variable AMP_DEBUG or const AMP_DEBUG = true and enable assertions for a stacktrace of the previous resolution.'; + // @codeCoverageIgnoreEnd + } + throw new \Error($message); + } + $phabel_39a51ba2e196654d = function () { + $env = \getenv("AMP_DEBUG") ?: "0"; + if ($env !== "0" && $env !== "false" || \defined("AMP_DEBUG") && \AMP_DEBUG) { + $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); + \array_shift($trace); + // remove current closure + $this->resolutionTrace = $trace; + } + return \true; + }; + \assert($phabel_39a51ba2e196654d()); + $this->complete = new Success(\false); + if ($this->waiting !== null) { + $waiting = $this->waiting; + $this->waiting = null; + $waiting->resolve($this->complete); + } + } + /** + * @param \Throwable $exception + * + * @return void + */ + private function fail(\Throwable $exception) + { + $this->complete = new Failure($exception); + if ($this->waiting !== null) { + $waiting = $this->waiting; + $this->waiting = null; + $waiting->resolve($this->complete); + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/Internal/ResolutionQueue.php b/vendor-bundle/amphp/amp/lib/Internal/ResolutionQueue.php new file mode 100644 index 000000000..09bb9c4b9 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Internal/ResolutionQueue.php @@ -0,0 +1,86 @@ +, mixed, + * mixed>|null) | callable(\Throwable|null, mixed): void> */ + private $queue = []; + /** + * @param callable|null $callback Initial callback to add to queue. + * + * @psalm-param null|callable(\Throwable|null, mixed): (Promise|\React\Promise\PromiseInterface|\Generator, mixed, + * mixed>|null) | callable(\Throwable|null, mixed): void $callback + */ + public function __construct(callable $callback = null) + { + if ($callback !== null) { + $this->push($callback); + } + } + /** + * Unrolls instances of self to avoid blowing up the call stack on resolution. + * + * @param callable $callback + * + * @psalm-param callable(\Throwable|null, mixed): (Promise|\React\Promise\PromiseInterface|\Generator, mixed, + * mixed>|null) | callable(\Throwable|null, mixed): void $callback + * + * @return void + */ + public function push(callable $callback) + { + if ($callback instanceof self) { + $this->queue = \array_merge($this->queue, $callback->queue); + return; + } + $this->queue[] = $callback; + } + /** + * Calls each callback in the queue, passing the provided values to the function. + * + * @param \Throwable|null $exception + * @param mixed $value + * + * @return void + */ + public function __invoke($exception, $value) + { + foreach ($this->queue as $callback) { + try { + $result = $callback($exception, $value); + if ($result === null) { + continue; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + Promise\rethrow($result); + } + } catch (\Exception $exception) { + Loop::defer(static function () use($exception) { + throw $exception; + }); + } catch (\Error $exception) { + Loop::defer(static function () use($exception) { + throw $exception; + }); + } + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/Internal/functions.php b/vendor-bundle/amphp/amp/lib/Internal/functions.php new file mode 100644 index 000000000..1cb3d3e68 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Internal/functions.php @@ -0,0 +1,138 @@ + $trace Output of + * `debug_backtrace()`. + * + * @return string Formatted stacktrace. + * + * @codeCoverageIgnore + * @internal + */ +function formatStacktrace(array $trace) +{ + $phabelReturn = \implode("\n", \array_map(static function ($e, $i) { + $line = "#{$i} "; + if (isset($e["file"])) { + $line .= "{$e['file']}:{$e['line']} "; + } + if (isset($e["type"])) { + $line .= $e["class"] . $e["type"]; + } + return $line . $e["function"] . "()"; + }, $trace, \array_keys($trace))); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; +} +/** + * Creates a `TypeError` with a standardized error message. + * + * @param string[] $expected Expected types. + * @param mixed $given Given value. + * + * @return \TypeError + * + * @internal + */ +function createTypeError(array $expected, $given) +{ + $givenType = \is_object($given) ? \sprintf("instance of %s", \get_class($given)) : \gettype($given); + if (\count($expected) === 1) { + $expectedType = "Expected the following type: " . \array_pop($expected); + } else { + $expectedType = "Expected one of the following types: " . \implode(", ", $expected); + } + $phabelReturn = new \TypeError("{$expectedType}; {$givenType} given"); + if (!$phabelReturn instanceof \TypeError) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type TypeError, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Returns the current time relative to an arbitrary point in time. + * + * @return int Time in milliseconds. + */ +function getCurrentTime() +{ + /** @var int|null $startTime */ + static $startTime; + /** @var int|null $nextWarning */ + static $nextWarning; + if (\PHP_INT_SIZE === 4) { + // @codeCoverageIgnoreStart + if ($startTime === null) { + $startTime = \PHP_VERSION_ID >= 70300 ? \hrtime(\false)[0] : \time(); + $nextWarning = \PHP_INT_MAX - 86400 * 7; + } + if (\PHP_VERSION_ID >= 70300) { + list($seconds, $nanoseconds) = \hrtime(\false); + $seconds -= $startTime; + if ($seconds >= $nextWarning) { + $timeToOverflow = (\PHP_INT_MAX - $seconds * 1000) / 1000; + \trigger_error("getCurrentTime() will overflow in {$timeToOverflow} seconds, please restart the process before that. " . "You're using a 32 bit version of PHP, so time will overflow about every 24 days. Regular restarts are required.", \E_USER_WARNING); + /** @psalm-suppress PossiblyNullOperand */ + $nextWarning += 600; + // every 10 minutes + } + $phabelReturn = (int) ($seconds * 1000 + $nanoseconds / 1000000); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + $seconds = \microtime(\true) - $startTime; + if ($seconds >= $nextWarning) { + $timeToOverflow = (\PHP_INT_MAX - $seconds * 1000) / 1000; + \trigger_error("getCurrentTime() will overflow in {$timeToOverflow} seconds, please restart the process before that. " . "You're using a 32 bit version of PHP, so time will overflow about every 24 days. Regular restarts are required.", \E_USER_WARNING); + /** @psalm-suppress PossiblyNullOperand */ + $nextWarning += 600; + // every 10 minutes + } + $phabelReturn = (int) ($seconds * 1000); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + // @codeCoverageIgnoreEnd + } + if (\PHP_VERSION_ID >= 70300) { + list($seconds, $nanoseconds) = \hrtime(\false); + $phabelReturn = (int) ($seconds * 1000 + $nanoseconds / 1000000); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = (int) (\microtime(\true) * 1000); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; +} diff --git a/vendor-bundle/amphp/amp/lib/InvalidYieldError.php b/vendor-bundle/amphp/amp/lib/InvalidYieldError.php new file mode 100644 index 000000000..afd22ce82 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/InvalidYieldError.php @@ -0,0 +1,34 @@ +current(); + $prefix .= \sprintf("; %s yielded at key %s", \is_object($yielded) ? \get_class($yielded) : \gettype($yielded), \var_export($generator->key(), \true)); + if (!$generator->valid()) { + parent::__construct($prefix, 0, $previous); + return; + } + $reflGen = new \ReflectionGenerator($generator); + $exeGen = $reflGen->getExecutingGenerator(); + if ($isSubgenerator = $exeGen !== $generator) { + $reflGen = new \ReflectionGenerator($exeGen); + } + parent::__construct(\sprintf("%s on line %s in %s", $prefix, $reflGen->getExecutingLine(), $reflGen->getExecutingFile()), 0, $previous); + } +} diff --git a/vendor-bundle/amphp/amp/lib/Iterator.php b/vendor-bundle/amphp/amp/lib/Iterator.php new file mode 100644 index 000000000..9f55682a8 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Iterator.php @@ -0,0 +1,33 @@ + + * + * @throws \Error If the prior promise returned from this method has not resolved. + * @throws \Throwable The exception used to fail the iterator. + */ + public function advance(); + /** + * Gets the last emitted value or throws an exception if the iterator has completed. + * + * @return mixed Value emitted from the iterator. + * @psalm-return TValue + * + * @throws \Error If the iterator has resolved or advance() was not called before calling this method. + * @throws \Throwable The exception used to fail the iterator. + */ + public function getCurrent(); +} diff --git a/vendor-bundle/amphp/amp/lib/LazyPromise.php b/vendor-bundle/amphp/amp/lib/LazyPromise.php new file mode 100644 index 000000000..b966ab60d --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/LazyPromise.php @@ -0,0 +1,38 @@ +promisor = $promisor; + } + /** + * {@inheritdoc} + */ + public function onResolve(callable $onResolved) + { + if ($this->promise === null) { + \assert($this->promisor !== null); + $provider = $this->promisor; + $this->promisor = null; + $this->promise = call($provider); + } + \assert($this->promise !== null); + $this->promise->onResolve($onResolved); + } +} diff --git a/vendor-bundle/amphp/amp/lib/Loop.php b/vendor-bundle/amphp/amp/lib/Loop.php new file mode 100644 index 000000000..e44a7753a --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Loop.php @@ -0,0 +1,573 @@ +defer($callback); + } + self::$driver->run(); + } + /** + * Stop the event loop. + * + * When an event loop is stopped, it continues with its current tick and exits the loop afterwards. Multiple calls + * to stop MUST be ignored and MUST NOT raise an exception. + * + * @return void + */ + public static function stop() + { + self::$driver->stop(); + } + /** + * Defer the execution of a callback. + * + * The deferred callable MUST be executed before any other type of watcher in a tick. Order of enabling MUST be + * preserved when executing the callbacks. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param callable(string $watcherId, mixed $data) $callback The callback to defer. The `$watcherId` will be + * invalidated before the callback call. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. + * + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. + */ + public static function defer(callable $callback, $data = null) + { + $phabelReturn = self::$driver->defer($callback, $data); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Delay the execution of a callback. + * + * The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which + * timers expire first, but timers with the same expiration time MAY be executed in any order. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param int $delay The amount of time, in milliseconds, to delay the execution for. + * @param callable(string $watcherId, mixed $data) $callback The callback to delay. The `$watcherId` will be + * invalidated before the callback call. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. + * + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. + */ + public static function delay($delay, callable $callback, $data = null) + { + if (!\is_int($delay)) { + if (!(\is_bool($delay) || \is_numeric($delay))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($delay) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($delay) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $delay = (int) $delay; + } + } + $phabelReturn = self::$driver->delay($delay, $callback, $data); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Repeatedly execute a callback. + * + * The interval between executions is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be + * determined by which timers expire first, but timers with the same expiration time MAY be executed in any order. + * The first execution is scheduled after the first interval period. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param int $interval The time interval, in milliseconds, to wait between executions. + * @param callable(string $watcherId, mixed $data) $callback The callback to repeat. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. + * + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. + */ + public static function repeat($interval, callable $callback, $data = null) + { + if (!\is_int($interval)) { + if (!(\is_bool($interval) || \is_numeric($interval))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($interval) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($interval) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $interval = (int) $interval; + } + } + $phabelReturn = self::$driver->repeat($interval, $callback, $data); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Execute a callback when a stream resource becomes readable or is closed for reading. + * + * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the + * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid + * resources, but are not required to, due to the high performance impact. Watchers on closed resources are + * therefore undefined behavior. + * + * Multiple watchers on the same stream MAY be executed in any order. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param resource $stream The stream to monitor. + * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. + * + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. + */ + public static function onReadable($stream, callable $callback, $data = null) + { + $phabelReturn = self::$driver->onReadable($stream, $callback, $data); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Execute a callback when a stream resource becomes writable or is closed for writing. + * + * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the + * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid + * resources, but are not required to, due to the high performance impact. Watchers on closed resources are + * therefore undefined behavior. + * + * Multiple watchers on the same stream MAY be executed in any order. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param resource $stream The stream to monitor. + * @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. + * + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. + */ + public static function onWritable($stream, callable $callback, $data = null) + { + $phabelReturn = self::$driver->onWritable($stream, $callback, $data); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Execute a callback when a signal is received. + * + * Warning: Installing the same signal on different instances of this interface is deemed undefined behavior. + * Implementations MAY try to detect this, if possible, but are not required to. This is due to technical + * limitations of the signals being registered globally per process. + * + * Multiple watchers on the same signal MAY be executed in any order. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param int $signo The signal number to monitor. + * @param callable(string $watcherId, int $signo, mixed $data) $callback The callback to execute. + * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. + * + * @throws UnsupportedFeatureException If signal handling is not supported. + */ + public static function onSignal($signo, callable $callback, $data = null) + { + if (!\is_int($signo)) { + if (!(\is_bool($signo) || \is_numeric($signo))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($signo) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signo) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signo = (int) $signo; + } + } + $phabelReturn = self::$driver->onSignal($signo, $callback, $data); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Enable a watcher to be active starting in the next tick. + * + * Watchers MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right before + * the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param string $watcherId The watcher identifier. + * + * @return void + * + * @throws InvalidWatcherError If the watcher identifier is invalid. + */ + public static function enable($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + self::$driver->enable($watcherId); + } + /** + * Disable a watcher immediately. + * + * A watcher MUST be disabled immediately, e.g. if a defer watcher disables a later defer watcher, the second defer + * watcher isn't executed in this tick. + * + * Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, even if passed an + * invalid watcher. + * + * @param string $watcherId The watcher identifier. + * + * @return void + */ + public static function disable($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + if (\PHP_VERSION_ID < 70200 && !isset(self::$driver)) { + // Prior to PHP 7.2, self::$driver may be unset during destruct. + // See https://github.com/amphp/amp/issues/212. + return; + } + self::$driver->disable($watcherId); + } + /** + * Cancel a watcher. + * + * This will detatch the event loop from all resources that are associated to the watcher. After this operation the + * watcher is permanently invalid. Calling this function MUST NOT fail, even if passed an invalid watcher. + * + * @param string $watcherId The watcher identifier. + * + * @return void + */ + public static function cancel($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + if (\PHP_VERSION_ID < 70200 && !isset(self::$driver)) { + // Prior to PHP 7.2, self::$driver may be unset during destruct. + // See https://github.com/amphp/amp/issues/212. + return; + } + self::$driver->cancel($watcherId); + } + /** + * Reference a watcher. + * + * This will keep the event loop alive whilst the watcher is still being monitored. Watchers have this state by + * default. + * + * @param string $watcherId The watcher identifier. + * + * @return void + * + * @throws InvalidWatcherError If the watcher identifier is invalid. + */ + public static function reference($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + self::$driver->reference($watcherId); + } + /** + * Unreference a watcher. + * + * The event loop should exit the run method when only unreferenced watchers are still being monitored. Watchers + * are all referenced by default. + * + * @param string $watcherId The watcher identifier. + * + * @return void + */ + public static function unreference($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + if (\PHP_VERSION_ID < 70200 && !isset(self::$driver)) { + // Prior to PHP 7.2, self::$driver may be unset during destruct. + // See https://github.com/amphp/amp/issues/212. + return; + } + self::$driver->unreference($watcherId); + } + /** + * Returns the current loop time in millisecond increments. Note this value does not necessarily correlate to + * wall-clock time, rather the value returned is meant to be used in relative comparisons to prior values returned + * by this method (intervals, expiration calculations, etc.) and is only updated once per loop tick. + * + * @return int + */ + public static function now() + { + $phabelReturn = self::$driver->now(); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Stores information in the loop bound registry. + * + * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages + * MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key. + * + * If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated + * interface for that purpose instead of sharing the storage key. + * + * @param string $key The namespaced storage key. + * @param mixed $value The value to be stored. + * + * @return void + */ + public static function setState($key, $value) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + self::$driver->setState($key, $value); + } + /** + * Gets information stored bound to the loop. + * + * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages + * MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key. + * + * If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated + * interface for that purpose instead of sharing the storage key. + * + * @param string $key The namespaced storage key. + * + * @return mixed The previously stored value or `null` if it doesn't exist. + */ + public static function getState($key) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + return self::$driver->getState($key); + } + /** + * Set a callback to be executed when an error occurs. + * + * The callback receives the error as the first and only parameter. The return value of the callback gets ignored. + * If it can't handle the error, it MUST throw the error. Errors thrown by the callback or during its invocation + * MUST be thrown into the `run` loop and stop the driver. + * + * Subsequent calls to this method will overwrite the previous handler. + * + * @param callable(\Throwable $error)|null $callback The callback to execute. `null` will clear the + * current handler. + * + * @return callable(\Throwable $error)|null The previous handler, `null` if there was none. + */ + public static function setErrorHandler(callable $callback = null) + { + return self::$driver->setErrorHandler($callback); + } + /** + * Retrieve an associative array of information about the event loop driver. + * + * The returned array MUST contain the following data describing the driver's currently registered watchers: + * + * [ + * "defer" => ["enabled" => int, "disabled" => int], + * "delay" => ["enabled" => int, "disabled" => int], + * "repeat" => ["enabled" => int, "disabled" => int], + * "on_readable" => ["enabled" => int, "disabled" => int], + * "on_writable" => ["enabled" => int, "disabled" => int], + * "on_signal" => ["enabled" => int, "disabled" => int], + * "enabled_watchers" => ["referenced" => int, "unreferenced" => int], + * "running" => bool + * ]; + * + * Implementations MAY optionally add more information in the array but at minimum the above `key => value` format + * MUST always be provided. + * + * @return array Statistics about the loop in the described format. + */ + public static function getInfo() + { + $phabelReturn = self::$driver->getInfo(); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Retrieve the event loop driver that is in scope. + * + * @return Driver + */ + public static function get() + { + $phabelReturn = self::$driver; + if (!$phabelReturn instanceof Driver) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Driver, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} +if (!\class_exists(PhabelAnonymousClassf66c86d93faee87e6cff006ff0599931355803a1ef8fc34109e457bffbf5fc844::class)) { + class PhabelAnonymousClassf66c86d93faee87e6cff006ff0599931355803a1ef8fc34109e457bffbf5fc844 extends Driver implements \Phabel\Target\Php70\AnonymousClass\AnonymousClassInterface + { + /** + * @return void + */ + protected function activate(array $watchers) + { + throw new \Error("Can't activate watcher during garbage collection."); + } + /** + * @return void + */ + protected function dispatch($blocking) + { + if (!\is_bool($blocking)) { + if (!(\is_bool($blocking) || \is_numeric($blocking) || \is_string($blocking))) { + throw new \TypeError(Driver::class . '@anonymous:' . __FUNCTION__ . '(): Argument #1 ($blocking) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($blocking) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $blocking = (bool) $blocking; + } + } + throw new \Error("Can't dispatch during garbage collection."); + } + /** + * @return void + */ + protected function deactivate(Watcher $watcher) + { + // do nothing + } + public function getHandle() + { + return null; + } + public static function getPhabelOriginalName() + { + return Driver::class . '@anonymous'; + } + } +} +// Default factory, don't move this to a file loaded by the composer "files" autoload mechanism, otherwise custom +// implementations might have issues setting a default loop, because it's overridden by us then. +// @codeCoverageIgnoreStart +Loop::set((new DriverFactory())->create()); +// @codeCoverageIgnoreEnd diff --git a/vendor-bundle/amphp/amp/lib/Loop/Driver.php b/vendor-bundle/amphp/amp/lib/Loop/Driver.php new file mode 100644 index 000000000..821087301 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Loop/Driver.php @@ -0,0 +1,799 @@ +running = \true; + try { + while ($this->running) { + if ($this->isEmpty()) { + return; + } + $this->tick(); + } + } finally { + $this->stop(); + } + } + /** + * @return bool True if no enabled and referenced watchers remain in the loop. + */ + private function isEmpty() + { + foreach ($this->watchers as $watcher) { + if ($watcher->enabled && $watcher->referenced) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + } + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Executes a single tick of the event loop. + * + * @return void + */ + private function tick() + { + if (empty($this->deferQueue)) { + $this->deferQueue = $this->nextTickQueue; + } else { + $this->deferQueue = \array_merge($this->deferQueue, $this->nextTickQueue); + } + $this->nextTickQueue = []; + $this->activate($this->enableQueue); + $this->enableQueue = []; + foreach ($this->deferQueue as $watcher) { + if (!isset($this->deferQueue[$watcher->id])) { + continue; + // Watcher disabled by another defer watcher. + } + unset($this->watchers[$watcher->id], $this->deferQueue[$watcher->id]); + try { + $phabel_56185a565d967e53 = $watcher->callback; + /** @var mixed $result */ + $result = $phabel_56185a565d967e53($watcher->id, $watcher->data); + if ($result === null) { + continue; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + } + /** @psalm-suppress RedundantCondition */ + $this->dispatch(empty($this->nextTickQueue) && empty($this->enableQueue) && $this->running && !$this->isEmpty()); + } + /** + * Activates (enables) all the given watchers. + * + * @param Watcher[] $watchers + * + * @return void + */ + protected abstract function activate(array $watchers); + /** + * Dispatches any pending read/write, timer, and signal events. + * + * @param bool $blocking + * + * @return void + */ + protected abstract function dispatch($blocking); + /** + * Stop the event loop. + * + * When an event loop is stopped, it continues with its current tick and exits the loop afterwards. Multiple calls + * to stop MUST be ignored and MUST NOT raise an exception. + * + * @return void + */ + public function stop() + { + $this->running = \false; + } + /** + * Defer the execution of a callback. + * + * The deferred callable MUST be executed before any other type of watcher in a tick. Order of enabling MUST be + * preserved when executing the callbacks. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param callable (string $watcherId, mixed $data) $callback The callback to defer. The `$watcherId` will be + * invalidated before the callback call. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. + * + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. + */ + public function defer(callable $callback, $data = null) + { + /** @psalm-var Watcher $watcher */ + $watcher = new Watcher(); + $watcher->type = Watcher::DEFER; + $watcher->id = $this->nextId++; + $watcher->callback = $callback; + $watcher->data = $data; + $this->watchers[$watcher->id] = $watcher; + $this->nextTickQueue[$watcher->id] = $watcher; + $phabelReturn = $watcher->id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Delay the execution of a callback. + * + * The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which + * timers expire first, but timers with the same expiration time MAY be executed in any order. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param int $delay The amount of time, in milliseconds, to delay the execution for. + * @param callable (string $watcherId, mixed $data) $callback The callback to delay. The `$watcherId` will be + * invalidated before the callback call. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. + * + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. + */ + public function delay($delay, callable $callback, $data = null) + { + if (!\is_int($delay)) { + if (!(\is_bool($delay) || \is_numeric($delay))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($delay) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($delay) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $delay = (int) $delay; + } + } + if ($delay < 0) { + throw new \Error("Delay must be greater than or equal to zero"); + } + /** @psalm-var Watcher $watcher */ + $watcher = new Watcher(); + $watcher->type = Watcher::DELAY; + $watcher->id = $this->nextId++; + $watcher->callback = $callback; + $watcher->value = $delay; + $watcher->expiration = $this->now() + $delay; + $watcher->data = $data; + $this->watchers[$watcher->id] = $watcher; + $this->enableQueue[$watcher->id] = $watcher; + $phabelReturn = $watcher->id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Repeatedly execute a callback. + * + * The interval between executions is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be + * determined by which timers expire first, but timers with the same expiration time MAY be executed in any order. + * The first execution is scheduled after the first interval period. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param int $interval The time interval, in milliseconds, to wait between executions. + * @param callable (string $watcherId, mixed $data) $callback The callback to repeat. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. + * + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. + */ + public function repeat($interval, callable $callback, $data = null) + { + if (!\is_int($interval)) { + if (!(\is_bool($interval) || \is_numeric($interval))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($interval) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($interval) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $interval = (int) $interval; + } + } + if ($interval < 0) { + throw new \Error("Interval must be greater than or equal to zero"); + } + /** @psalm-var Watcher $watcher */ + $watcher = new Watcher(); + $watcher->type = Watcher::REPEAT; + $watcher->id = $this->nextId++; + $watcher->callback = $callback; + $watcher->value = $interval; + $watcher->expiration = $this->now() + $interval; + $watcher->data = $data; + $this->watchers[$watcher->id] = $watcher; + $this->enableQueue[$watcher->id] = $watcher; + $phabelReturn = $watcher->id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Execute a callback when a stream resource becomes readable or is closed for reading. + * + * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the + * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid + * resources, but are not required to, due to the high performance impact. Watchers on closed resources are + * therefore undefined behavior. + * + * Multiple watchers on the same stream MAY be executed in any order. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param resource $stream The stream to monitor. + * @param callable (string $watcherId, resource $stream, mixed $data) $callback The callback to execute. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. + * + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. + */ + public function onReadable($stream, callable $callback, $data = null) + { + /** @psalm-var Watcher $watcher */ + $watcher = new Watcher(); + $watcher->type = Watcher::READABLE; + $watcher->id = $this->nextId++; + $watcher->callback = $callback; + $watcher->value = $stream; + $watcher->data = $data; + $this->watchers[$watcher->id] = $watcher; + $this->enableQueue[$watcher->id] = $watcher; + $phabelReturn = $watcher->id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Execute a callback when a stream resource becomes writable or is closed for writing. + * + * Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the + * watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid + * resources, but are not required to, due to the high performance impact. Watchers on closed resources are + * therefore undefined behavior. + * + * Multiple watchers on the same stream MAY be executed in any order. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param resource $stream The stream to monitor. + * @param callable (string $watcherId, resource $stream, mixed $data) $callback The callback to execute. + * @param mixed $data Arbitrary data given to the callback function as the `$data` parameter. + * + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. + */ + public function onWritable($stream, callable $callback, $data = null) + { + /** @psalm-var Watcher $watcher */ + $watcher = new Watcher(); + $watcher->type = Watcher::WRITABLE; + $watcher->id = $this->nextId++; + $watcher->callback = $callback; + $watcher->value = $stream; + $watcher->data = $data; + $this->watchers[$watcher->id] = $watcher; + $this->enableQueue[$watcher->id] = $watcher; + $phabelReturn = $watcher->id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Execute a callback when a signal is received. + * + * Warning: Installing the same signal on different instances of this interface is deemed undefined behavior. + * Implementations MAY try to detect this, if possible, but are not required to. This is due to technical + * limitations of the signals being registered globally per process. + * + * Multiple watchers on the same signal MAY be executed in any order. + * + * The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called) + * right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param int $signo The signal number to monitor. + * @param callable (string $watcherId, int $signo, mixed $data) $callback The callback to execute. + * @param mixed $data Arbitrary data given to the callback function as the $data parameter. + * + * @return string An unique identifier that can be used to cancel, enable or disable the watcher. + * + * @throws UnsupportedFeatureException If signal handling is not supported. + */ + public function onSignal($signo, callable $callback, $data = null) + { + if (!\is_int($signo)) { + if (!(\is_bool($signo) || \is_numeric($signo))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($signo) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signo) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signo = (int) $signo; + } + } + /** @psalm-var Watcher $watcher */ + $watcher = new Watcher(); + $watcher->type = Watcher::SIGNAL; + $watcher->id = $this->nextId++; + $watcher->callback = $callback; + $watcher->value = $signo; + $watcher->data = $data; + $this->watchers[$watcher->id] = $watcher; + $this->enableQueue[$watcher->id] = $watcher; + $phabelReturn = $watcher->id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Enable a watcher to be active starting in the next tick. + * + * Watchers MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right before + * the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled. + * + * @param string $watcherId The watcher identifier. + * + * @return void + * + * @throws InvalidWatcherError If the watcher identifier is invalid. + */ + public function enable($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + if (!isset($this->watchers[$watcherId])) { + throw new InvalidWatcherError($watcherId, "Cannot enable an invalid watcher identifier: '{$watcherId}'"); + } + $watcher = $this->watchers[$watcherId]; + if ($watcher->enabled) { + return; + // Watcher already enabled. + } + $watcher->enabled = \true; + switch ($watcher->type) { + case Watcher::DEFER: + $this->nextTickQueue[$watcher->id] = $watcher; + break; + case Watcher::REPEAT: + case Watcher::DELAY: + \assert(\is_int($watcher->value)); + $watcher->expiration = $this->now() + $watcher->value; + $this->enableQueue[$watcher->id] = $watcher; + break; + default: + $this->enableQueue[$watcher->id] = $watcher; + break; + } + } + /** + * Cancel a watcher. + * + * This will detach the event loop from all resources that are associated to the watcher. After this operation the + * watcher is permanently invalid. Calling this function MUST NOT fail, even if passed an invalid watcher. + * + * @param string $watcherId The watcher identifier. + * + * @return void + */ + public function cancel($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + $this->disable($watcherId); + unset($this->watchers[$watcherId]); + } + /** + * Disable a watcher immediately. + * + * A watcher MUST be disabled immediately, e.g. if a defer watcher disables a later defer watcher, the second defer + * watcher isn't executed in this tick. + * + * Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, even if passed an + * invalid watcher. + * + * @param string $watcherId The watcher identifier. + * + * @return void + */ + public function disable($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + if (!isset($this->watchers[$watcherId])) { + return; + } + $watcher = $this->watchers[$watcherId]; + if (!$watcher->enabled) { + return; + // Watcher already disabled. + } + $watcher->enabled = \false; + $id = $watcher->id; + switch ($watcher->type) { + case Watcher::DEFER: + if (isset($this->nextTickQueue[$id])) { + // Watcher was only queued to be enabled. + unset($this->nextTickQueue[$id]); + } else { + unset($this->deferQueue[$id]); + } + break; + default: + if (isset($this->enableQueue[$id])) { + // Watcher was only queued to be enabled. + unset($this->enableQueue[$id]); + } else { + $this->deactivate($watcher); + } + break; + } + } + /** + * Deactivates (disables) the given watcher. + * + * @param Watcher $watcher + * + * @return void + */ + protected abstract function deactivate(Watcher $watcher); + /** + * Reference a watcher. + * + * This will keep the event loop alive whilst the watcher is still being monitored. Watchers have this state by + * default. + * + * @param string $watcherId The watcher identifier. + * + * @return void + * + * @throws InvalidWatcherError If the watcher identifier is invalid. + */ + public function reference($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + if (!isset($this->watchers[$watcherId])) { + throw new InvalidWatcherError($watcherId, "Cannot reference an invalid watcher identifier: '{$watcherId}'"); + } + $this->watchers[$watcherId]->referenced = \true; + } + /** + * Unreference a watcher. + * + * The event loop should exit the run method when only unreferenced watchers are still being monitored. Watchers + * are all referenced by default. + * + * @param string $watcherId The watcher identifier. + * + * @return void + */ + public function unreference($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + if (!isset($this->watchers[$watcherId])) { + return; + } + $this->watchers[$watcherId]->referenced = \false; + } + /** + * Stores information in the loop bound registry. + * + * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages + * MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key. + * + * If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated + * interface for that purpose instead of sharing the storage key. + * + * @param string $key The namespaced storage key. + * @param mixed $value The value to be stored. + * + * @return void + */ + public final function setState($key, $value) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + if ($value === null) { + unset($this->registry[$key]); + } else { + $this->registry[$key] = $value; + } + } + /** + * Gets information stored bound to the loop. + * + * Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages + * MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key. + * + * If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated + * interface for that purpose instead of sharing the storage key. + * + * @param string $key The namespaced storage key. + * + * @return mixed The previously stored value or `null` if it doesn't exist. + */ + public final function getState($key) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + return isset($this->registry[$key]) ? $this->registry[$key] : null; + } + /** + * Set a callback to be executed when an error occurs. + * + * The callback receives the error as the first and only parameter. The return value of the callback gets ignored. + * If it can't handle the error, it MUST throw the error. Errors thrown by the callback or during its invocation + * MUST be thrown into the `run` loop and stop the driver. + * + * Subsequent calls to this method will overwrite the previous handler. + * + * @param callable(\Throwable $error):void|null $callback The callback to execute. `null` will clear the + * current handler. + * + * @return callable(\Throwable $error):void|null The previous handler, `null` if there was none. + */ + public function setErrorHandler(callable $callback = null) + { + $previous = $this->errorHandler; + $this->errorHandler = $callback; + return $previous; + } + /** + * Invokes the error handler with the given exception. + * + * @param \Throwable $exception The exception thrown from a watcher callback. + * + * @return void + * @throws \Throwable If no error handler has been set. + */ + protected function error(\Throwable $exception) + { + if ($this->errorHandler === null) { + throw $exception; + } + $phabel_6170bbb6d7be24ff = $this->errorHandler; + $phabel_6170bbb6d7be24ff($exception); + } + /** + * Returns the current loop time in millisecond increments. Note this value does not necessarily correlate to + * wall-clock time, rather the value returned is meant to be used in relative comparisons to prior values returned + * by this method (intervals, expiration calculations, etc.) and is only updated once per loop tick. + * + * Extending classes should override this function to return a value cached once per loop tick. + * + * @return int + */ + public function now() + { + $phabelReturn = (int) (\microtime(\true) * self::MILLISEC_PER_SEC); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Get the underlying loop handle. + * + * Example: the `uv_loop` resource for `libuv` or the `EvLoop` object for `libev` or `null` for a native driver. + * + * Note: This function is *not* exposed in the `Loop` class. Users shall access it directly on the respective loop + * instance. + * + * @return null|object|resource The loop handle the event loop operates on. `null` if there is none. + */ + public abstract function getHandle(); + /** + * Returns the same array of data as getInfo(). + * + * @return array + */ + public function __debugInfo() + { + // @codeCoverageIgnoreStart + return $this->getInfo(); + // @codeCoverageIgnoreEnd + } + /** + * Retrieve an associative array of information about the event loop driver. + * + * The returned array MUST contain the following data describing the driver's currently registered watchers: + * + * [ + * "defer" => ["enabled" => int, "disabled" => int], + * "delay" => ["enabled" => int, "disabled" => int], + * "repeat" => ["enabled" => int, "disabled" => int], + * "on_readable" => ["enabled" => int, "disabled" => int], + * "on_writable" => ["enabled" => int, "disabled" => int], + * "on_signal" => ["enabled" => int, "disabled" => int], + * "enabled_watchers" => ["referenced" => int, "unreferenced" => int], + * "running" => bool + * ]; + * + * Implementations MAY optionally add more information in the array but at minimum the above `key => value` format + * MUST always be provided. + * + * @return array Statistics about the loop in the described format. + */ + public function getInfo() + { + $watchers = ["referenced" => 0, "unreferenced" => 0]; + $defer = $delay = $repeat = $onReadable = $onWritable = $onSignal = ["enabled" => 0, "disabled" => 0]; + foreach ($this->watchers as $watcher) { + switch ($watcher->type) { + case Watcher::READABLE: + $array =& $onReadable; + break; + case Watcher::WRITABLE: + $array =& $onWritable; + break; + case Watcher::SIGNAL: + $array =& $onSignal; + break; + case Watcher::DEFER: + $array =& $defer; + break; + case Watcher::DELAY: + $array =& $delay; + break; + case Watcher::REPEAT: + $array =& $repeat; + break; + default: + // @codeCoverageIgnoreStart + throw new \Error("Unknown watcher type"); + } + if ($watcher->enabled) { + ++$array["enabled"]; + if ($watcher->referenced) { + ++$watchers["referenced"]; + } else { + ++$watchers["unreferenced"]; + } + } else { + ++$array["disabled"]; + } + } + $phabelReturn = ["enabled_watchers" => $watchers, "defer" => $defer, "delay" => $delay, "repeat" => $repeat, "on_readable" => $onReadable, "on_writable" => $onWritable, "on_signal" => $onSignal, "running" => (bool) $this->running]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/amp/lib/Loop/DriverFactory.php b/vendor-bundle/amphp/amp/lib/Loop/DriverFactory.php new file mode 100644 index 000000000..77848ae72 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Loop/DriverFactory.php @@ -0,0 +1,64 @@ +createDriverFromEnv()) { + return $driver; + } + if (UvDriver::isSupported()) { + return new UvDriver(); + } + if (EvDriver::isSupported()) { + return new EvDriver(); + } + if (EventDriver::isSupported()) { + return new EventDriver(); + } + return new NativeDriver(); + }; + $driver = $phabel_42ba52b6ad07a742(); + if (\getenv("AMP_DEBUG_TRACE_WATCHERS")) { + $phabelReturn = new TracingDriver($driver); + if (!$phabelReturn instanceof Driver) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Driver, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = $driver; + if (!$phabelReturn instanceof Driver) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Driver, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return Driver|null + */ + private function createDriverFromEnv() + { + $driver = \getenv("AMP_LOOP_DRIVER"); + if (!$driver) { + return null; + } + if (!\class_exists($driver)) { + throw new \Error(\sprintf("Driver '%s' does not exist.", $driver)); + } + if (!\is_subclass_of($driver, Driver::class)) { + throw new \Error(\sprintf("Driver '%s' is not a subclass of '%s'.", $driver, Driver::class)); + } + return new $driver(); + } +} +// @codeCoverageIgnoreEnd diff --git a/vendor-bundle/amphp/amp/lib/Loop/EvDriver.php b/vendor-bundle/amphp/amp/lib/Loop/EvDriver.php new file mode 100644 index 000000000..9d0ada3b9 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Loop/EvDriver.php @@ -0,0 +1,301 @@ +handle = new \EvLoop(); + $this->nowOffset = getCurrentTime(); + $this->now = \random_int(0, $this->nowOffset); + $this->nowOffset -= $this->now; + if (self::$activeSignals === null) { + self::$activeSignals =& $this->signals; + } + /** + * @param \EvIO $event + * + * @return void + */ + $this->ioCallback = function (\Phabel\EvIO $event) { + /** @var Watcher $watcher */ + $watcher = $event->data; + try { + $phabel_67d4713590c776b8 = $watcher->callback; + $result = $phabel_67d4713590c776b8($watcher->id, $watcher->value, $watcher->data); + if ($result === null) { + return; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + }; + /** + * @param \EvTimer $event + * + * @return void + */ + $this->timerCallback = function (\EvTimer $event) { + /** @var Watcher $watcher */ + $watcher = $event->data; + if ($watcher->type & Watcher::DELAY) { + $this->cancel($watcher->id); + } elseif ($watcher->value === 0) { + // Disable and re-enable so it's not executed repeatedly in the same tick + // See https://github.com/amphp/amp/issues/131 + $this->disable($watcher->id); + $this->enable($watcher->id); + } + try { + $phabel_db4cea38c7f7e4d4 = $watcher->callback; + $result = $phabel_db4cea38c7f7e4d4($watcher->id, $watcher->data); + if ($result === null) { + return; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + }; + /** + * @param \EvSignal $event + * + * @return void + */ + $this->signalCallback = function (\EvSignal $event) { + /** @var Watcher $watcher */ + $watcher = $event->data; + try { + $phabel_b61c41162565f9e0 = $watcher->callback; + $result = $phabel_b61c41162565f9e0($watcher->id, $watcher->value, $watcher->data); + if ($result === null) { + return; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + }; + } + /** + * {@inheritdoc} + */ + public function cancel($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + parent::cancel($watcherId); + unset($this->events[$watcherId]); + } + public function __destruct() + { + foreach ($this->events as $event) { + /** @psalm-suppress all */ + if ($event !== null) { + // Events may have been nulled in extension depending on destruct order. + $event->stop(); + } + } + // We need to clear all references to events manually, see + // https://bitbucket.org/osmanov/pecl-ev/issues/31/segfault-in-ev_timer_stop + $this->events = []; + } + /** + * {@inheritdoc} + */ + public function run() + { + $active = self::$activeSignals; + \assert($active !== null); + foreach ($active as $event) { + $event->stop(); + } + self::$activeSignals =& $this->signals; + foreach ($this->signals as $event) { + $event->start(); + } + try { + parent::run(); + } finally { + foreach ($this->signals as $event) { + $event->stop(); + } + self::$activeSignals =& $active; + foreach ($active as $event) { + $event->start(); + } + } + } + /** + * {@inheritdoc} + */ + public function stop() + { + $this->handle->stop(); + parent::stop(); + } + /** + * {@inheritdoc} + */ + public function now() + { + $this->now = getCurrentTime() - $this->nowOffset; + $phabelReturn = $this->now; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function getHandle() + { + $phabelReturn = $this->handle; + if (!$phabelReturn instanceof \EvLoop) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type EvLoop, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + * + * @return void + */ + protected function dispatch($blocking) + { + if (!\is_bool($blocking)) { + if (!(\is_bool($blocking) || \is_numeric($blocking) || \is_string($blocking))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($blocking) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($blocking) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $blocking = (bool) $blocking; + } + } + $this->handle->run($blocking ? \Ev::RUN_ONCE : \Ev::RUN_ONCE | \Ev::RUN_NOWAIT); + } + /** + * {@inheritdoc} + * + * @return void + */ + protected function activate(array $watchers) + { + $this->handle->nowUpdate(); + $now = $this->now(); + foreach ($watchers as $watcher) { + if (!isset($this->events[$id = $watcher->id])) { + switch ($watcher->type) { + case Watcher::READABLE: + \assert(\is_resource($watcher->value)); + $this->events[$id] = $this->handle->io($watcher->value, \Ev::READ, $this->ioCallback, $watcher); + break; + case Watcher::WRITABLE: + \assert(\is_resource($watcher->value)); + $this->events[$id] = $this->handle->io($watcher->value, \Ev::WRITE, $this->ioCallback, $watcher); + break; + case Watcher::DELAY: + case Watcher::REPEAT: + \assert(\is_int($watcher->value)); + $interval = $watcher->value / self::MILLISEC_PER_SEC; + $this->events[$id] = $this->handle->timer(\max(0, ($watcher->expiration - $now) / self::MILLISEC_PER_SEC), $watcher->type & Watcher::REPEAT ? $interval : 0, $this->timerCallback, $watcher); + break; + case Watcher::SIGNAL: + \assert(\is_int($watcher->value)); + $this->events[$id] = $this->handle->signal($watcher->value, $this->signalCallback, $watcher); + break; + default: + // @codeCoverageIgnoreStart + throw new \Error("Unknown watcher type"); + } + } else { + $this->events[$id]->start(); + } + if ($watcher->type === Watcher::SIGNAL) { + /** @psalm-suppress PropertyTypeCoercion */ + $this->signals[$id] = $this->events[$id]; + } + } + } + /** + * {@inheritdoc} + * + * @return void + */ + protected function deactivate(Watcher $watcher) + { + if (isset($this->events[$id = $watcher->id])) { + $this->events[$id]->stop(); + if ($watcher->type === Watcher::SIGNAL) { + unset($this->signals[$id]); + } + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/Loop/EventDriver.php b/vendor-bundle/amphp/amp/lib/Loop/EventDriver.php new file mode 100644 index 000000000..0682a80ef --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Loop/EventDriver.php @@ -0,0 +1,320 @@ +handle = new \EventBase(); + $this->nowOffset = getCurrentTime(); + $this->now = \random_int(0, $this->nowOffset); + $this->nowOffset -= $this->now; + if (self::$activeSignals === null) { + self::$activeSignals =& $this->signals; + } + /** + * @param $resource + * @param $what + * @param Watcher $watcher + * + * @return void + */ + $this->ioCallback = function ($resource, $what, Watcher $watcher) { + \assert(\is_resource($watcher->value)); + try { + $phabel_d42ef1497e567626 = $watcher->callback; + $result = $phabel_d42ef1497e567626($watcher->id, $watcher->value, $watcher->data); + if ($result === null) { + return; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + }; + /** + * @param $resource + * @param $what + * @param Watcher $watcher + * + * @return void + */ + $this->timerCallback = function ($resource, $what, Watcher $watcher) { + \assert(\is_int($watcher->value)); + if ($watcher->type & Watcher::DELAY) { + $this->cancel($watcher->id); + } else { + $this->events[$watcher->id]->add($watcher->value / self::MILLISEC_PER_SEC); + } + try { + $phabel_f4797f4ec6dbeccc = $watcher->callback; + $result = $phabel_f4797f4ec6dbeccc($watcher->id, $watcher->data); + if ($result === null) { + return; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + }; + /** + * @param $signum + * @param $what + * @param Watcher $watcher + * + * @return void + */ + $this->signalCallback = function ($signum, $what, Watcher $watcher) { + try { + $phabel_220d72e73a2c8658 = $watcher->callback; + $result = $phabel_220d72e73a2c8658($watcher->id, $watcher->value, $watcher->data); + if ($result === null) { + return; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + }; + } + /** + * {@inheritdoc} + */ + public function cancel($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + parent::cancel($watcherId); + if (isset($this->events[$watcherId])) { + $this->events[$watcherId]->free(); + unset($this->events[$watcherId]); + } + } + public static function isSupported() + { + $phabelReturn = \extension_loaded("event"); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @codeCoverageIgnore + */ + public function __destruct() + { + foreach ($this->events as $event) { + if ($event !== null) { + // Events may have been nulled in extension depending on destruct order. + $event->free(); + } + } + // Unset here, otherwise $event->del() fails with a warning, because __destruct order isn't defined. + // See https://github.com/amphp/amp/issues/159. + $this->events = []; + // Manually free the loop handle to fully release loop resources. + // See https://github.com/amphp/amp/issues/177. + if ($this->handle !== null) { + $this->handle->free(); + $this->handle = null; + } + } + /** + * {@inheritdoc} + */ + public function run() + { + $active = self::$activeSignals; + \assert($active !== null); + foreach ($active as $event) { + $event->del(); + } + self::$activeSignals =& $this->signals; + foreach ($this->signals as $event) { + /** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */ + $event->add(); + } + try { + parent::run(); + } finally { + foreach ($this->signals as $event) { + $event->del(); + } + self::$activeSignals =& $active; + foreach ($active as $event) { + /** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */ + $event->add(); + } + } + } + /** + * {@inheritdoc} + */ + public function stop() + { + $this->handle->stop(); + parent::stop(); + } + /** + * {@inheritdoc} + */ + public function now() + { + $this->now = getCurrentTime() - $this->nowOffset; + $phabelReturn = $this->now; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function getHandle() + { + $phabelReturn = $this->handle; + if (!$phabelReturn instanceof \EventBase) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type EventBase, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + * + * @return void + */ + protected function dispatch($blocking) + { + if (!\is_bool($blocking)) { + if (!(\is_bool($blocking) || \is_numeric($blocking) || \is_string($blocking))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($blocking) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($blocking) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $blocking = (bool) $blocking; + } + } + $this->handle->loop($blocking ? \EventBase::LOOP_ONCE : \EventBase::LOOP_ONCE | \EventBase::LOOP_NONBLOCK); + } + /** + * {@inheritdoc} + * + * @return void + */ + protected function activate(array $watchers) + { + $now = $this->now(); + foreach ($watchers as $watcher) { + if (!isset($this->events[$id = $watcher->id])) { + switch ($watcher->type) { + case Watcher::READABLE: + \assert(\is_resource($watcher->value)); + $this->events[$id] = new \Event($this->handle, $watcher->value, \Event::READ | \Event::PERSIST, $this->ioCallback, $watcher); + break; + case Watcher::WRITABLE: + \assert(\is_resource($watcher->value)); + $this->events[$id] = new \Event($this->handle, $watcher->value, \Event::WRITE | \Event::PERSIST, $this->ioCallback, $watcher); + break; + case Watcher::DELAY: + case Watcher::REPEAT: + \assert(\is_int($watcher->value)); + $this->events[$id] = new \Event($this->handle, -1, \Event::TIMEOUT, $this->timerCallback, $watcher); + break; + case Watcher::SIGNAL: + \assert(\is_int($watcher->value)); + $this->events[$id] = new \Event($this->handle, $watcher->value, \Event::SIGNAL | \Event::PERSIST, $this->signalCallback, $watcher); + break; + default: + // @codeCoverageIgnoreStart + throw new \Error("Unknown watcher type"); + } + } + switch ($watcher->type) { + case Watcher::DELAY: + case Watcher::REPEAT: + \assert(\is_int($watcher->value)); + $interval = \max(0, $watcher->expiration - $now); + $this->events[$id]->add($interval > 0 ? $interval / self::MILLISEC_PER_SEC : 0); + break; + case Watcher::SIGNAL: + $this->signals[$id] = $this->events[$id]; + // no break + default: + /** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */ + $this->events[$id]->add(); + break; + } + } + } + /** + * {@inheritdoc} + * + * @return void + */ + protected function deactivate(Watcher $watcher) + { + if (isset($this->events[$id = $watcher->id])) { + $this->events[$id]->del(); + if ($watcher->type === Watcher::SIGNAL) { + unset($this->signals[$id]); + } + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/Loop/Internal/TimerQueue.php b/vendor-bundle/amphp/amp/lib/Loop/Internal/TimerQueue.php new file mode 100644 index 000000000..43f3b1146 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Loop/Internal/TimerQueue.php @@ -0,0 +1,189 @@ +data[$node]; + while ($node !== 0 && $entry->expiration < $this->data[$parent = $node - 1 >> 1]->expiration) { + $this->swap($node, $parent); + $node = $parent; + } + } + /** + * @param int $node Rebuild the data array from the given node downward. + * + * @return void + */ + private function heapifyDown($node) + { + if (!\is_int($node)) { + if (!(\is_bool($node) || \is_numeric($node))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($node) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($node) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $node = (int) $node; + } + } + $length = \count($this->data); + while (($child = ($node << 1) + 1) < $length) { + if ($this->data[$child]->expiration < $this->data[$node]->expiration && ($child + 1 >= $length || $this->data[$child]->expiration < $this->data[$child + 1]->expiration)) { + // Left child is less than parent and right child. + $swap = $child; + } elseif ($child + 1 < $length && $this->data[$child + 1]->expiration < $this->data[$node]->expiration) { + // Right child is less than parent and left child. + $swap = $child + 1; + } else { + // Left and right child are greater than parent. + break; + } + $this->swap($node, $swap); + $node = $swap; + } + } + private function swap($left, $right) + { + if (!\is_int($left)) { + if (!(\is_bool($left) || \is_numeric($left))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($left) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($left) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $left = (int) $left; + } + } + if (!\is_int($right)) { + if (!(\is_bool($right) || \is_numeric($right))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($right) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($right) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $right = (int) $right; + } + } + $temp = $this->data[$left]; + $this->data[$left] = $this->data[$right]; + $this->pointers[$this->data[$right]->id] = $left; + $this->data[$right] = $temp; + $this->pointers[$temp->id] = $right; + } + /** + * Inserts the watcher into the queue. Time complexity: O(log(n)). + * + * @param Watcher $watcher + * + * @psalm-param Watcher $watcher + * + * @return void + */ + public function insert(Watcher $watcher) + { + \assert($watcher->expiration !== null); + \assert(!isset($this->pointers[$watcher->id])); + $node = \count($this->data); + $this->data[$node] = $watcher; + $this->pointers[$watcher->id] = $node; + $this->heapifyUp($node); + } + /** + * Removes the given watcher from the queue. Time complexity: O(log(n)). + * + * @param Watcher $watcher + * + * @psalm-param Watcher $watcher + * + * @return void + */ + public function remove(Watcher $watcher) + { + $id = $watcher->id; + if (!isset($this->pointers[$id])) { + return; + } + $this->removeAndRebuild($this->pointers[$id]); + } + /** + * Deletes and returns the Watcher on top of the heap if it has expired, otherwise null is returned. + * Time complexity: O(log(n)). + * + * @param int $now Current loop time. + * + * @return Watcher|null Expired watcher at the top of the heap or null if the watcher has not expired. + * + * @psalm-return Watcher|null + */ + public function extract($now) + { + if (!\is_int($now)) { + if (!(\is_bool($now) || \is_numeric($now))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($now) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($now) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $now = (int) $now; + } + } + if (empty($this->data)) { + return null; + } + $watcher = $this->data[0]; + if ($watcher->expiration > $now) { + return null; + } + $this->removeAndRebuild(0); + return $watcher; + } + /** + * Returns the expiration time value at the top of the heap. Time complexity: O(1). + * + * @return int|null Expiration time of the watcher at the top of the heap or null if the heap is empty. + */ + public function peek() + { + return isset($this->data[0]) ? $this->data[0]->expiration : null; + } + /** + * @param int $node Remove the given node and then rebuild the data array. + * + * @return void + */ + private function removeAndRebuild($node) + { + if (!\is_int($node)) { + if (!(\is_bool($node) || \is_numeric($node))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($node) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($node) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $node = (int) $node; + } + } + $length = \count($this->data) - 1; + $id = $this->data[$node]->id; + $left = $this->data[$node] = $this->data[$length]; + $this->pointers[$left->id] = $node; + unset($this->data[$length], $this->pointers[$id]); + if ($node < $length) { + // don't need to do anything if we removed the last element + $parent = $node - 1 >> 1; + if ($parent >= 0 && $this->data[$node]->expiration < $this->data[$parent]->expiration) { + $this->heapifyUp($node); + } else { + $this->heapifyDown($node); + } + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/Loop/InvalidWatcherError.php b/vendor-bundle/amphp/amp/lib/Loop/InvalidWatcherError.php new file mode 100644 index 000000000..dfe7db0c7 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Loop/InvalidWatcherError.php @@ -0,0 +1,44 @@ +watcherId = $watcherId; + parent::__construct($message); + } + /** + * @return string The watcher identifier. + */ + public function getWatcherId() + { + return $this->watcherId; + } +} diff --git a/vendor-bundle/amphp/amp/lib/Loop/NativeDriver.php b/vendor-bundle/amphp/amp/lib/Loop/NativeDriver.php new file mode 100644 index 000000000..e10ec97dd --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Loop/NativeDriver.php @@ -0,0 +1,437 @@ +timerQueue = new Internal\TimerQueue(); + $this->signalHandling = \extension_loaded("pcntl"); + $this->nowOffset = getCurrentTime(); + $this->now = \random_int(0, $this->nowOffset); + $this->nowOffset -= $this->now; + $this->streamSelectErrorHandler = function ($errno, $message) { + // Casing changed in PHP 8 from 'unable' to 'Unable' + if (\stripos($message, "stream_select(): unable to select [4]: ") === 0) { + // EINTR + $this->streamSelectIgnoreResult = \true; + return; + } + if (\strpos($message, 'FD_SETSIZE') !== \false) { + $message = \str_replace(["\r\n", "\n", "\r"], " ", $message); + $pattern = '(stream_select\\(\\): You MUST recompile PHP with a larger value of FD_SETSIZE. It is set to (\\d+), but you have descriptors numbered at least as high as (\\d+)\\.)'; + if (\preg_match($pattern, $message, $match)) { + $helpLink = 'https://amphp.org/amp/event-loop/#implementations'; + $message = 'You have reached the limits of stream_select(). It has a FD_SETSIZE of ' . $match[1] . ', but you have file descriptors numbered at least as high as ' . $match[2] . '. ' . "You can install one of the extensions listed on {$helpLink} to support a higher number of " . 'concurrent file descriptors. If a large number of open file descriptors is unexpected, you might be leaking file descriptors that aren\'t closed correctly.'; + } + } + throw new \Exception($message, $errno); + }; + } + /** + * {@inheritdoc} + * + * @throws \Amp\Loop\UnsupportedFeatureException If the pcntl extension is not available. + */ + public function onSignal($signo, callable $callback, $data = null) + { + if (!\is_int($signo)) { + if (!(\is_bool($signo) || \is_numeric($signo))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($signo) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signo) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signo = (int) $signo; + } + } + if (!$this->signalHandling) { + throw new UnsupportedFeatureException("Signal handling requires the pcntl extension"); + } + $phabelReturn = parent::onSignal($signo, $callback, $data); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function now() + { + $this->now = getCurrentTime() - $this->nowOffset; + $phabelReturn = $this->now; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function getHandle() + { + return null; + } + /** + * @param bool $blocking + * + * @return void + * + * @throws \Throwable + */ + protected function dispatch($blocking) + { + if (!\is_bool($blocking)) { + if (!(\is_bool($blocking) || \is_numeric($blocking) || \is_string($blocking))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($blocking) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($blocking) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $blocking = (bool) $blocking; + } + } + $this->selectStreams($this->readStreams, $this->writeStreams, $blocking ? $this->getTimeout() : 0); + $now = $this->now(); + while ($watcher = $this->timerQueue->extract($now)) { + if ($watcher->type & Watcher::REPEAT) { + $watcher->enabled = \false; + // Trick base class into adding to enable queue when calling enable() + $this->enable($watcher->id); + } else { + $this->cancel($watcher->id); + } + try { + $phabel_a422fc52460a9b50 = $watcher->callback; + // Execute the timer. + $result = $phabel_a422fc52460a9b50($watcher->id, $watcher->data); + if ($result === null) { + continue; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + } + if ($this->signalHandling) { + \pcntl_signal_dispatch(); + } + } + /** + * {@inheritdoc} + * + * @return void + */ + protected function activate(array $watchers) + { + foreach ($watchers as $watcher) { + switch ($watcher->type) { + case Watcher::READABLE: + \assert(\is_resource($watcher->value)); + $streamId = (int) $watcher->value; + $this->readWatchers[$streamId][$watcher->id] = $watcher; + $this->readStreams[$streamId] = $watcher->value; + break; + case Watcher::WRITABLE: + \assert(\is_resource($watcher->value)); + $streamId = (int) $watcher->value; + $this->writeWatchers[$streamId][$watcher->id] = $watcher; + $this->writeStreams[$streamId] = $watcher->value; + break; + case Watcher::DELAY: + case Watcher::REPEAT: + \assert(\is_int($watcher->value)); + $this->timerQueue->insert($watcher); + break; + case Watcher::SIGNAL: + \assert(\is_int($watcher->value)); + if (!isset($this->signalWatchers[$watcher->value])) { + if (!@\pcntl_signal($watcher->value, $this->callableFromInstanceMethod('handleSignal'))) { + $message = "Failed to register signal handler"; + if ($error = \error_get_last()) { + $message .= \sprintf("; Errno: %d; %s", $error["type"], $error["message"]); + } + throw new \Error($message); + } + } + $this->signalWatchers[$watcher->value][$watcher->id] = $watcher; + break; + default: + // @codeCoverageIgnoreStart + throw new \Error("Unknown watcher type"); + } + } + } + /** + * {@inheritdoc} + * + * @return void + */ + protected function deactivate(Watcher $watcher) + { + switch ($watcher->type) { + case Watcher::READABLE: + $streamId = (int) $watcher->value; + unset($this->readWatchers[$streamId][$watcher->id]); + if (empty($this->readWatchers[$streamId])) { + unset($this->readWatchers[$streamId], $this->readStreams[$streamId]); + } + break; + case Watcher::WRITABLE: + $streamId = (int) $watcher->value; + unset($this->writeWatchers[$streamId][$watcher->id]); + if (empty($this->writeWatchers[$streamId])) { + unset($this->writeWatchers[$streamId], $this->writeStreams[$streamId]); + } + break; + case Watcher::DELAY: + case Watcher::REPEAT: + $this->timerQueue->remove($watcher); + break; + case Watcher::SIGNAL: + \assert(\is_int($watcher->value)); + if (isset($this->signalWatchers[$watcher->value])) { + unset($this->signalWatchers[$watcher->value][$watcher->id]); + if (empty($this->signalWatchers[$watcher->value])) { + unset($this->signalWatchers[$watcher->value]); + @\pcntl_signal($watcher->value, \SIG_DFL); + } + } + break; + default: + // @codeCoverageIgnoreStart + throw new \Error("Unknown watcher type"); + } + } + /** + * @param resource[] $read + * @param resource[] $write + * @param int $timeout + * + * @return void + */ + private function selectStreams(array $read, array $write, $timeout) + { + if (!\is_int($timeout)) { + if (!(\is_bool($timeout) || \is_numeric($timeout))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($timeout) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeout) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $timeout = (int) $timeout; + } + } + $timeout /= self::MILLISEC_PER_SEC; + if (!empty($read) || !empty($write)) { + // Use stream_select() if there are any streams in the loop. + if ($timeout >= 0) { + $seconds = (int) $timeout; + $microseconds = (int) (($timeout - $seconds) * self::MICROSEC_PER_SEC); + } else { + $seconds = null; + $microseconds = null; + } + // Failed connection attempts are indicated via except on Windows + // @link https://github.com/reactphp/event-loop/blob/8bd064ce23c26c4decf186c2a5a818c9a8209eb0/src/StreamSelectLoop.php#L279-L287 + // @link https://docs.microsoft.com/de-de/windows/win32/api/winsock2/nf-winsock2-select + $except = null; + if (\DIRECTORY_SEPARATOR === '\\') { + $except = $write; + } + \set_error_handler($this->streamSelectErrorHandler); + try { + $result = \stream_select($read, $write, $except, $seconds, $microseconds); + } finally { + \restore_error_handler(); + } + if ($this->streamSelectIgnoreResult || $result === 0) { + $this->streamSelectIgnoreResult = \false; + return; + } + if (!$result) { + $this->error(new \Exception('Unknown error during stream_select')); + return; + } + foreach ($read as $stream) { + $streamId = (int) $stream; + if (!isset($this->readWatchers[$streamId])) { + continue; + // All read watchers disabled. + } + foreach ($this->readWatchers[$streamId] as $watcher) { + if (!isset($this->readWatchers[$streamId][$watcher->id])) { + continue; + // Watcher disabled by another IO watcher. + } + try { + $phabel_668b107f3be16641 = $watcher->callback; + $result = $phabel_668b107f3be16641($watcher->id, $stream, $watcher->data); + if ($result === null) { + continue; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + } + } + \assert(\is_array($write)); + // See https://github.com/vimeo/psalm/issues/3036 + if ($except) { + foreach ($except as $key => $socket) { + $write[$key] = $socket; + } + } + foreach ($write as $stream) { + $streamId = (int) $stream; + if (!isset($this->writeWatchers[$streamId])) { + continue; + // All write watchers disabled. + } + foreach ($this->writeWatchers[$streamId] as $watcher) { + if (!isset($this->writeWatchers[$streamId][$watcher->id])) { + continue; + // Watcher disabled by another IO watcher. + } + try { + $phabel_d881bf449cdca21d = $watcher->callback; + $result = $phabel_d881bf449cdca21d($watcher->id, $stream, $watcher->data); + if ($result === null) { + continue; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + } + } + return; + } + if ($timeout < 0) { + // Only signal watchers are enabled, so sleep indefinitely. + \usleep(\PHP_INT_MAX); + return; + } + if ($timeout > 0) { + // Sleep until next timer expires. + \usleep((int) ($timeout * self::MICROSEC_PER_SEC)); + } + } + /** + * @return int Milliseconds until next timer expires or -1 if there are no pending times. + */ + private function getTimeout() + { + $expiration = $this->timerQueue->peek(); + if ($expiration === null) { + $phabelReturn = -1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + $expiration -= getCurrentTime() - $this->nowOffset; + $phabelReturn = $expiration > 0 ? $expiration : 0; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @param int $signo + * + * @return void + */ + private function handleSignal($signo) + { + if (!\is_int($signo)) { + if (!(\is_bool($signo) || \is_numeric($signo))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($signo) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signo) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signo = (int) $signo; + } + } + foreach ($this->signalWatchers[$signo] as $watcher) { + if (!isset($this->signalWatchers[$signo][$watcher->id])) { + continue; + } + try { + $phabel_cb9626d52af40a29 = $watcher->callback; + $result = $phabel_cb9626d52af40a29($watcher->id, $signo, $watcher->data); + if ($result === null) { + continue; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/Loop/TracingDriver.php b/vendor-bundle/amphp/amp/lib/Loop/TracingDriver.php new file mode 100644 index 000000000..727852b75 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Loop/TracingDriver.php @@ -0,0 +1,392 @@ +driver = $driver; + } + public function run() + { + $this->driver->run(); + } + public function stop() + { + $this->driver->stop(); + } + public function defer(callable $callback, $data = null) + { + $id = $this->driver->defer(function (...$args) use($callback) { + $this->cancel($args[0]); + return $callback(...$args); + }, $data); + $this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); + $this->enabledWatchers[$id] = \true; + $phabelReturn = $id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function delay($delay, callable $callback, $data = null) + { + if (!\is_int($delay)) { + if (!(\is_bool($delay) || \is_numeric($delay))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($delay) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($delay) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $delay = (int) $delay; + } + } + $id = $this->driver->delay($delay, function (...$args) use($callback) { + $this->cancel($args[0]); + return $callback(...$args); + }, $data); + $this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); + $this->enabledWatchers[$id] = \true; + $phabelReturn = $id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function repeat($interval, callable $callback, $data = null) + { + if (!\is_int($interval)) { + if (!(\is_bool($interval) || \is_numeric($interval))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($interval) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($interval) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $interval = (int) $interval; + } + } + $id = $this->driver->repeat($interval, $callback, $data); + $this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); + $this->enabledWatchers[$id] = \true; + $phabelReturn = $id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function onReadable($stream, callable $callback, $data = null) + { + $id = $this->driver->onReadable($stream, $callback, $data); + $this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); + $this->enabledWatchers[$id] = \true; + $phabelReturn = $id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function onWritable($stream, callable $callback, $data = null) + { + $id = $this->driver->onWritable($stream, $callback, $data); + $this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); + $this->enabledWatchers[$id] = \true; + $phabelReturn = $id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function onSignal($signo, callable $callback, $data = null) + { + if (!\is_int($signo)) { + if (!(\is_bool($signo) || \is_numeric($signo))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($signo) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signo) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signo = (int) $signo; + } + } + $id = $this->driver->onSignal($signo, $callback, $data); + $this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); + $this->enabledWatchers[$id] = \true; + $phabelReturn = $id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function enable($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + try { + $this->driver->enable($watcherId); + $this->enabledWatchers[$watcherId] = \true; + } catch (InvalidWatcherError $e) { + throw new InvalidWatcherError($watcherId, $e->getMessage() . "\r\n\r\n" . $this->getTraces($watcherId)); + } + } + public function cancel($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + $this->driver->cancel($watcherId); + if (!isset($this->cancelTraces[$watcherId])) { + $this->cancelTraces[$watcherId] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS)); + } + unset($this->enabledWatchers[$watcherId], $this->unreferencedWatchers[$watcherId]); + } + public function disable($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + $this->driver->disable($watcherId); + unset($this->enabledWatchers[$watcherId]); + } + public function reference($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + try { + $this->driver->reference($watcherId); + unset($this->unreferencedWatchers[$watcherId]); + } catch (InvalidWatcherError $e) { + throw new InvalidWatcherError($watcherId, $e->getMessage() . "\r\n\r\n" . $this->getTraces($watcherId)); + } + } + public function unreference($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + $this->driver->unreference($watcherId); + $this->unreferencedWatchers[$watcherId] = \true; + } + public function setErrorHandler(callable $callback = null) + { + return $this->driver->setErrorHandler($callback); + } + /** @inheritdoc */ + public function getHandle() + { + $this->driver->getHandle(); + } + public function dump() + { + $dump = "Enabled, referenced watchers keeping the loop running: "; + foreach ($this->enabledWatchers as $watcher => $_) { + if (isset($this->unreferencedWatchers[$watcher])) { + continue; + } + $dump .= "Watcher ID: " . $watcher . "\r\n"; + $dump .= $this->getCreationTrace($watcher); + $dump .= "\r\n\r\n"; + } + $phabelReturn = \rtrim($dump); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function getInfo() + { + $phabelReturn = $this->driver->getInfo(); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function __debugInfo() + { + return $this->driver->__debugInfo(); + } + public function now() + { + $phabelReturn = $this->driver->now(); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + protected function error(\Throwable $exception) + { + $this->driver->error($exception); + } + /** + * @inheritdoc + * + * @return void + */ + protected function activate(array $watchers) + { + // nothing to do in a decorator + } + /** + * @inheritdoc + * + * @return void + */ + protected function dispatch($blocking) + { + if (!\is_bool($blocking)) { + if (!(\is_bool($blocking) || \is_numeric($blocking) || \is_string($blocking))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($blocking) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($blocking) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $blocking = (bool) $blocking; + } + } + // nothing to do in a decorator + } + /** + * @inheritdoc + * + * @return void + */ + protected function deactivate(Watcher $watcher) + { + // nothing to do in a decorator + } + private function getTraces($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + $phabelReturn = "Creation Trace:\r\n" . $this->getCreationTrace($watcherId) . ' + +Cancellation Trace: +' . $this->getCancelTrace($watcherId); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + private function getCreationTrace($watcher) + { + if (!\is_string($watcher)) { + if (!(\is_string($watcher) || \is_object($watcher) && \method_exists($watcher, '__toString') || (\is_bool($watcher) || \is_numeric($watcher)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcher) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcher) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcher = (string) $watcher; + } + } + if (!isset($this->creationTraces[$watcher])) { + $phabelReturn = 'No creation trace, yet.'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = $this->creationTraces[$watcher]; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + private function getCancelTrace($watcher) + { + if (!\is_string($watcher)) { + if (!(\is_string($watcher) || \is_object($watcher) && \method_exists($watcher, '__toString') || (\is_bool($watcher) || \is_numeric($watcher)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcher) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcher) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcher = (string) $watcher; + } + } + if (!isset($this->cancelTraces[$watcher])) { + $phabelReturn = 'No cancellation trace, yet.'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = $this->cancelTraces[$watcher]; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/amp/lib/Loop/UnsupportedFeatureException.php b/vendor-bundle/amphp/amp/lib/Loop/UnsupportedFeatureException.php new file mode 100644 index 000000000..e5b826098 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Loop/UnsupportedFeatureException.php @@ -0,0 +1,12 @@ +handle = \uv_loop_new(); + /** + * @param $event + * @param $status + * @param $events + * @param $resource + * + * @return void + */ + $this->ioCallback = function ($event, $status, $events, $resource) { + $watchers = $this->watchers[(int) $event]; + switch ($status) { + case 0: + // OK + break; + default: + // Invoke the callback on errors, as this matches behavior with other loop back-ends. + // Re-enable watcher as libuv disables the watcher on non-zero status. + $flags = 0; + foreach ($watchers as $watcher) { + $flags |= $watcher->enabled ? $watcher->type : 0; + } + \uv_poll_start($event, $flags, $this->ioCallback); + break; + } + foreach ($watchers as $watcher) { + // $events is OR'ed with 4 to trigger watcher if no events are indicated (0) or on UV_DISCONNECT (4). + // http://docs.libuv.org/en/v1.x/poll.html + if (!($watcher->enabled && ($watcher->type & $events || ($events | 4) === 4))) { + continue; + } + try { + $phabel_2e845441a9ab246b = $watcher->callback; + $result = $phabel_2e845441a9ab246b($watcher->id, $resource, $watcher->data); + if ($result === null) { + continue; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + } + }; + /** + * @param $event + * + * @return void + */ + $this->timerCallback = function ($event) { + $watcher = $this->watchers[(int) $event][0]; + if ($watcher->type & Watcher::DELAY) { + unset($this->events[$watcher->id], $this->watchers[(int) $event]); + // Avoid call to uv_is_active(). + $this->cancel($watcher->id); + // Remove reference to watcher in parent. + } elseif ($watcher->value === 0) { + // Disable and re-enable so it's not executed repeatedly in the same tick + // See https://github.com/amphp/amp/issues/131 + $this->disable($watcher->id); + $this->enable($watcher->id); + } + try { + $phabel_db5f43921a822918 = $watcher->callback; + $result = $phabel_db5f43921a822918($watcher->id, $watcher->data); + if ($result === null) { + return; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + }; + /** + * @param $event + * @param $signo + * + * @return void + */ + $this->signalCallback = function ($event, $signo) { + $watcher = $this->watchers[(int) $event][0]; + try { + $phabel_825278b93725b9b6 = $watcher->callback; + $result = $phabel_825278b93725b9b6($watcher->id, $signo, $watcher->data); + if ($result === null) { + return; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + rethrow($result); + } + } catch (\Exception $exception) { + $this->error($exception); + } catch (\Error $exception) { + $this->error($exception); + } + }; + } + /** + * {@inheritdoc} + */ + public function cancel($watcherId) + { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + parent::cancel($watcherId); + if (!isset($this->events[$watcherId])) { + return; + } + $event = $this->events[$watcherId]; + $eventId = (int) $event; + if (isset($this->watchers[$eventId][0])) { + // All except IO watchers. + unset($this->watchers[$eventId]); + } elseif (isset($this->watchers[$eventId][$watcherId])) { + $watcher = $this->watchers[$eventId][$watcherId]; + unset($this->watchers[$eventId][$watcherId]); + if (empty($this->watchers[$eventId])) { + unset($this->watchers[$eventId], $this->streams[(int) $watcher->value]); + } + } + unset($this->events[$watcherId]); + } + public static function isSupported() + { + $phabelReturn = \extension_loaded("uv"); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function now() + { + \uv_update_time($this->handle); + $phabelReturn = \uv_now($this->handle); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + /** @psalm-suppress TooManyArguments */ + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function getHandle() + { + return $this->handle; + } + /** + * {@inheritdoc} + * + * @return void + */ + protected function dispatch($blocking) + { + if (!\is_bool($blocking)) { + if (!(\is_bool($blocking) || \is_numeric($blocking) || \is_string($blocking))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($blocking) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($blocking) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $blocking = (bool) $blocking; + } + } + /** @psalm-suppress TooManyArguments */ + \uv_run($this->handle, $blocking ? \UV::RUN_ONCE : \UV::RUN_NOWAIT); + } + /** + * {@inheritdoc} + * + * @return void + */ + protected function activate(array $watchers) + { + $now = $this->now(); + foreach ($watchers as $watcher) { + $id = $watcher->id; + switch ($watcher->type) { + case Watcher::READABLE: + case Watcher::WRITABLE: + \assert(\is_resource($watcher->value)); + $streamId = (int) $watcher->value; + if (isset($this->streams[$streamId])) { + $event = $this->streams[$streamId]; + } elseif (isset($this->events[$id])) { + $event = $this->streams[$streamId] = $this->events[$id]; + } else { + /** @psalm-suppress UndefinedFunction */ + $event = $this->streams[$streamId] = \Phabel\uv_poll_init_socket($this->handle, $watcher->value); + } + $eventId = (int) $event; + $this->events[$id] = $event; + $this->watchers[$eventId][$id] = $watcher; + $flags = 0; + foreach ($this->watchers[$eventId] as $w) { + $flags |= $w->enabled ? $w->type : 0; + } + \uv_poll_start($event, $flags, $this->ioCallback); + break; + case Watcher::DELAY: + case Watcher::REPEAT: + \assert(\is_int($watcher->value)); + if (isset($this->events[$id])) { + $event = $this->events[$id]; + } else { + $event = $this->events[$id] = \uv_timer_init($this->handle); + } + $this->watchers[(int) $event] = [$watcher]; + \uv_timer_start($event, \max(0, $watcher->expiration - $now), $watcher->type & Watcher::REPEAT ? $watcher->value : 0, $this->timerCallback); + break; + case Watcher::SIGNAL: + \assert(\is_int($watcher->value)); + if (isset($this->events[$id])) { + $event = $this->events[$id]; + } else { + /** @psalm-suppress UndefinedFunction */ + $event = $this->events[$id] = \Phabel\uv_signal_init($this->handle); + } + $this->watchers[(int) $event] = [$watcher]; + /** @psalm-suppress UndefinedFunction */ + \Phabel\uv_signal_start($event, $this->signalCallback, $watcher->value); + break; + default: + // @codeCoverageIgnoreStart + throw new \Error("Unknown watcher type"); + } + } + } + /** + * {@inheritdoc} + * + * @return void + */ + protected function deactivate(Watcher $watcher) + { + $id = $watcher->id; + if (!isset($this->events[$id])) { + return; + } + $event = $this->events[$id]; + if (!\uv_is_active($event)) { + return; + } + switch ($watcher->type) { + case Watcher::READABLE: + case Watcher::WRITABLE: + $flags = 0; + foreach ($this->watchers[(int) $event] as $w) { + $flags |= $w->enabled ? $w->type : 0; + } + if ($flags) { + \uv_poll_start($event, $flags, $this->ioCallback); + } else { + \uv_poll_stop($event); + } + break; + case Watcher::DELAY: + case Watcher::REPEAT: + \uv_timer_stop($event); + break; + case Watcher::SIGNAL: + \uv_signal_stop($event); + break; + default: + // @codeCoverageIgnoreStart + throw new \Error("Unknown watcher type"); + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/Loop/Watcher.php b/vendor-bundle/amphp/amp/lib/Loop/Watcher.php new file mode 100644 index 000000000..00c9825e5 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Loop/Watcher.php @@ -0,0 +1,47 @@ +reasons = $reasons; + } + /** + * @return \Throwable[] + */ + public function getReasons() + { + $phabelReturn = $this->reasons; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/amp/lib/NullCancellationToken.php b/vendor-bundle/amphp/amp/lib/NullCancellationToken.php new file mode 100644 index 000000000..3af621a8e --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/NullCancellationToken.php @@ -0,0 +1,73 @@ +throwIfRequested(); + * } + * ``` + * + * potentially multiple times, it allows writing + * + * ```php + * $token = $token ?? new NullCancellationToken; + * + * // ... + * + * $token->throwIfRequested(); + * ``` + * + * instead. + */ +final class NullCancellationToken implements CancellationToken +{ + /** @inheritdoc */ + public function subscribe(callable $callback) + { + $phabelReturn = "null-token"; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** @inheritdoc */ + public function unsubscribe($id) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + // nothing to do + } + /** @inheritdoc */ + public function isRequested() + { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** @inheritdoc */ + public function throwIfRequested() + { + // nothing to do + } +} diff --git a/vendor-bundle/amphp/amp/lib/Producer.php b/vendor-bundle/amphp/amp/lib/Producer.php new file mode 100644 index 000000000..001ea0561 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Producer.php @@ -0,0 +1,38 @@ + + */ +final class Producer implements Iterator +{ + /** + * @use Internal\Producer + */ + use CallableMaker, Internal\Producer; + /** + * @param callable(callable(TValue):Promise):\Generator $producer + * + * @throws \Error Thrown if the callable does not return a Generator. + */ + public function __construct(callable $producer) + { + $result = $producer($this->callableFromInstanceMethod("emit")); + if (!$result instanceof \Generator) { + throw new \Error("The callable did not return a Generator"); + } + $coroutine = new Coroutine($result); + $coroutine->onResolve(function ($exception) { + if ($this->complete) { + return; + } + if ($exception) { + $this->fail($exception); + return; + } + $this->complete(); + }); + } +} diff --git a/vendor-bundle/amphp/amp/lib/Promise.php b/vendor-bundle/amphp/amp/lib/Promise.php new file mode 100644 index 000000000..64c4134fe --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Promise.php @@ -0,0 +1,37 @@ +, mixed, + * mixed>|null) | callable(\Throwable|null, mixed): void $onResolved + * + * @return void + */ + public function onResolve(callable $onResolved); +} diff --git a/vendor-bundle/amphp/amp/lib/Struct.php b/vendor-bundle/amphp/amp/lib/Struct.php new file mode 100644 index 000000000..9e299d821 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Struct.php @@ -0,0 +1,112 @@ +generateStructPropertyError($property)); + } + /** + * @param string $property + * @param mixed $value + * + * @psalm-return no-return + */ + public function __set($property, $value) + { + if (!\is_string($property)) { + if (!(\is_string($property) || \is_object($property) && \method_exists($property, '__toString') || (\is_bool($property) || \is_numeric($property)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($property) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($property) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $property = (string) $property; + } + } + throw new \Error($this->generateStructPropertyError($property)); + } + private function generateStructPropertyError($property) + { + if (!\is_string($property)) { + if (!(\is_string($property) || \is_object($property) && \method_exists($property, '__toString') || (\is_bool($property) || \is_numeric($property)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($property) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($property) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $property = (string) $property; + } + } + $suggestion = $this->suggestPropertyName($property); + $suggestStr = $suggestion == "" ? "" : " ... did you mean \"{$suggestion}?\""; + $phabelReturn = \sprintf( + "%s property \"%s\" does not exist%s", + \str_replace("\x00", "@", \get_class($this)), + // Handle anonymous class names. + $property, + $suggestStr + ); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + private function suggestPropertyName($badProperty) + { + if (!\is_string($badProperty)) { + if (!(\is_string($badProperty) || \is_object($badProperty) && \method_exists($badProperty, '__toString') || (\is_bool($badProperty) || \is_numeric($badProperty)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($badProperty) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($badProperty) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $badProperty = (string) $badProperty; + } + } + $badProperty = \strtolower($badProperty); + $bestMatch = ""; + $bestMatchPercentage = 0; + /** @psalm-suppress RawObjectIteration */ + foreach ($this as $property => $value) { + // Never suggest properties that begin with an underscore + if ($property[0] === "_") { + continue; + } + \similar_text($badProperty, \strtolower($property), $byRefPercentage); + if ($byRefPercentage > $bestMatchPercentage) { + $bestMatchPercentage = $byRefPercentage; + $bestMatch = $property; + } + } + $phabelReturn = $bestMatchPercentage >= $this->__propertySuggestThreshold ? $bestMatch : ""; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/amp/lib/Success.php b/vendor-bundle/amphp/amp/lib/Success.php new file mode 100644 index 000000000..d6547de62 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/Success.php @@ -0,0 +1,57 @@ + + */ +final class Success implements Promise +{ + /** @var mixed */ + private $value; + /** + * @param mixed $value Anything other than a Promise object. + * + * @psalm-param TValue $value + * + * @throws \Error If a promise is given as the value. + */ + public function __construct($value = null) + { + if ($value instanceof Promise || $value instanceof ReactPromise) { + throw new \Error("Cannot use a promise as success value"); + } + $this->value = $value; + } + /** + * {@inheritdoc} + */ + public function onResolve(callable $onResolved) + { + try { + $result = $onResolved(null, $this->value); + if ($result === null) { + return; + } + if ($result instanceof \Generator) { + $result = new Coroutine($result); + } + if ($result instanceof Promise || $result instanceof ReactPromise) { + Promise\rethrow($result); + } + } catch (\Exception $exception) { + Loop::defer(static function () use($exception) { + throw $exception; + }); + } catch (\Error $exception) { + Loop::defer(static function () use($exception) { + throw $exception; + }); + } + } +} diff --git a/vendor-bundle/amphp/amp/lib/TimeoutCancellationToken.php b/vendor-bundle/amphp/amp/lib/TimeoutCancellationToken.php new file mode 100644 index 000000000..334accaf8 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/TimeoutCancellationToken.php @@ -0,0 +1,102 @@ +token = $source->getToken(); + $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); + $this->watcher = Loop::delay($timeout, static function () use($source, $message, $trace) { + $trace = formatStacktrace($trace); + $source->cancel(new TimeoutException("{$message}\r\nTimeoutCancellationToken was created here:\r\n{$trace}")); + }); + Loop::unreference($this->watcher); + } + /** + * Cancels the delay watcher. + */ + public function __destruct() + { + Loop::cancel($this->watcher); + } + /** + * {@inheritdoc} + */ + public function subscribe(callable $callback) + { + $phabelReturn = $this->token->subscribe($callback); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function unsubscribe($id) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + $this->token->unsubscribe($id); + } + /** + * {@inheritdoc} + */ + public function isRequested() + { + $phabelReturn = $this->token->isRequested(); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function throwIfRequested() + { + $this->token->throwIfRequested(); + } +} diff --git a/vendor-bundle/amphp/amp/lib/TimeoutException.php b/vendor-bundle/amphp/amp/lib/TimeoutException.php new file mode 100644 index 000000000..7047b54f5 --- /dev/null +++ b/vendor-bundle/amphp/amp/lib/TimeoutException.php @@ -0,0 +1,26 @@ + + * @template T as TReturn|Promise|\Generator + * + * @formatter:off + * + * @param callable(...mixed): T $callback + * + * @return callable + * @psalm-return (T is Promise ? (callable(mixed...): Promise) : (T is \Generator ? (TGenerator is Promise ? (callable(mixed...): Promise) : (callable(mixed...): Promise)) : (callable(mixed...): Promise))) + * + * @formatter:on + * + * @see asyncCoroutine() + * + * @psalm-suppress InvalidReturnType + */ +function coroutine(callable $callback) +{ + $phabelReturn = static function (...$args) use($callback) { + $phabelReturn = call($callback, ...$args); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + }; + if (!\is_callable($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** @psalm-suppress InvalidReturnStatement */ + return $phabelReturn; +} +/** + * Returns a new function that wraps $callback in a promise/coroutine-aware function that automatically runs + * Generators as coroutines. The returned function always returns void when invoked. Errors are forwarded to the + * loop's error handler using `Amp\Promise\rethrow()`. + * + * Use this function to create a coroutine-aware callable for a non-promise-aware callback caller. + * + * @param callable(...mixed): mixed $callback + * + * @return callable + * @psalm-return callable(mixed...): void + * + * @see coroutine() + */ +function asyncCoroutine(callable $callback) +{ + $phabelReturn = static function (...$args) use($callback) { + Promise\rethrow(call($callback, ...$args)); + }; + if (!\is_callable($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Calls the given function, always returning a promise. If the function returns a Generator, it will be run as a + * coroutine. If the function throws, a failed promise will be returned. + * + * @template TReturn + * @template TPromise + * @template TGeneratorReturn + * @template TGeneratorPromise + * + * @template TGenerator as TGeneratorReturn|Promise + * @template T as TReturn|Promise|\Generator + * + * @formatter:off + * + * @param callable(...mixed): T $callback + * @param mixed ...$args Arguments to pass to the function. + * + * @return Promise + * @psalm-return (T is Promise ? Promise : (T is \Generator ? (TGenerator is Promise ? Promise : Promise) : Promise)) + * + * @formatter:on + */ +function call(callable $callback, ...$args) +{ + try { + $result = $callback(...$args); + } catch (\Exception $exception) { + $phabelReturn = new Failure($exception); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } catch (\Error $exception) { + $phabelReturn = new Failure($exception); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($result instanceof \Generator) { + $phabelReturn = new Coroutine($result); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($result instanceof Promise) { + $phabelReturn = $result; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($result instanceof ReactPromise) { + $phabelReturn = Promise\adapt($result); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = new Success($result); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Calls the given function. If the function returns a Generator, it will be run as a coroutine. If the function + * throws or returns a failing promise, the failure is forwarded to the loop error handler. + * + * @param callable(...mixed): mixed $callback + * @param mixed ...$args Arguments to pass to the function. + * + * @return void + */ +function asyncCall(callable $callback, ...$args) +{ + Promise\rethrow(call($callback, ...$args)); +} +/** + * Sleeps for the specified number of milliseconds. + * + * @param int $milliseconds + * + * @return Delayed + */ +function delay($milliseconds) +{ + if (!\is_int($milliseconds)) { + if (!(\is_bool($milliseconds) || \is_numeric($milliseconds))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($milliseconds) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($milliseconds) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $milliseconds = (int) $milliseconds; + } + } + $phabelReturn = new Delayed($milliseconds); + if (!$phabelReturn instanceof Delayed) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Delayed, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Returns the current time relative to an arbitrary point in time. + * + * @return int Time in milliseconds. + */ +function getCurrentTime() +{ + $phabelReturn = Internal\getCurrentTime(); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; +} +namespace Phabel\Amp\Promise; + +use Phabel\Amp\Deferred; +use Phabel\Amp\Loop; +use Phabel\Amp\MultiReasonException; +use Phabel\Amp\Promise; +use Phabel\Amp\Success; +use Phabel\Amp\TimeoutException; +use Phabel\React\Promise\PromiseInterface as ReactPromise; +use function Phabel\Amp\call; +use function Phabel\Amp\Internal\createTypeError; +/** + * Registers a callback that will forward the failure reason to the event loop's error handler if the promise fails. + * + * Use this function if you neither return the promise nor handle a possible error yourself to prevent errors from + * going entirely unnoticed. + * + * @param Promise|ReactPromise $promise Promise to register the handler on. + * + * @return void + * @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface. + * + */ +function rethrow($promise) +{ + if (!$promise instanceof Promise) { + if ($promise instanceof ReactPromise) { + $promise = adapt($promise); + } else { + throw createTypeError([Promise::class, ReactPromise::class], $promise); + } + } + $promise->onResolve(static function ($exception) { + if ($exception) { + throw $exception; + } + }); +} +/** + * Runs the event loop until the promise is resolved. Should not be called within a running event loop. + * + * Use this function only in synchronous contexts to wait for an asynchronous operation. Use coroutines and yield to + * await promise resolution in a fully asynchronous application instead. + * + * @template TPromise + * @template T as Promise|ReactPromise + * + * @param Promise|ReactPromise $promise Promise to wait for. + * + * @return mixed Promise success value. + * + * @psalm-param T $promise + * @psalm-return (T is Promise ? TPromise : mixed) + * + * @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface. + * @throws \Error If the event loop stopped without the $promise being resolved. + * @throws \Throwable Promise failure reason. + */ +function wait($promise) +{ + if (!$promise instanceof Promise) { + if ($promise instanceof ReactPromise) { + $promise = adapt($promise); + } else { + throw createTypeError([Promise::class, ReactPromise::class], $promise); + } + } + $resolved = \false; + try { + Loop::run(function () use(&$resolved, &$value, &$exception, $promise) { + $promise->onResolve(function ($e, $v) use(&$resolved, &$value, &$exception) { + Loop::stop(); + $resolved = \true; + $exception = $e; + $value = $v; + }); + }); + } catch (\Exception $throwable) { + throw new \Error("Loop exceptionally stopped without resolving the promise", 0, $throwable); + } catch (\Error $throwable) { + throw new \Error("Loop exceptionally stopped without resolving the promise", 0, $throwable); + } + if (!$resolved) { + throw new \Error("Loop stopped without resolving the promise"); + } + if ($exception) { + throw $exception; + } + return $value; +} +/** + * Creates an artificial timeout for any `Promise`. + * + * If the timeout expires before the promise is resolved, the returned promise fails with an instance of + * `Amp\TimeoutException`. + * + * @template TReturn + * + * @param Promise|ReactPromise $promise Promise to which the timeout is applied. + * @param int $timeout Timeout in milliseconds. + * + * @return Promise + * + * @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface. + */ +function timeout($promise, $timeout) +{ + if (!\is_int($timeout)) { + if (!(\is_bool($timeout) || \is_numeric($timeout))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($timeout) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeout) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $timeout = (int) $timeout; + } + } + if (!$promise instanceof Promise) { + if ($promise instanceof ReactPromise) { + $promise = adapt($promise); + } else { + throw createTypeError([Promise::class, ReactPromise::class], $promise); + } + } + $deferred = new Deferred(); + $watcher = Loop::delay($timeout, static function () use(&$deferred) { + $temp = $deferred; + // prevent double resolve + $deferred = null; + $temp->fail(new TimeoutException()); + }); + Loop::unreference($watcher); + $promise->onResolve(function () use(&$deferred, $promise, $watcher) { + if ($deferred !== null) { + Loop::cancel($watcher); + $deferred->resolve($promise); + } + }); + $phabelReturn = $deferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Creates an artificial timeout for any `Promise`. + * + * If the promise is resolved before the timeout expires, the result is returned + * + * If the timeout expires before the promise is resolved, a default value is returned + * + * @template TReturn + * + * @param Promise|ReactPromise $promise Promise to which the timeout is applied. + * @param int $timeout Timeout in milliseconds. + * @param TReturn $default + * + * @return Promise + * + * @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface. + */ +function timeoutWithDefault($promise, $timeout, $default = null) +{ + if (!\is_int($timeout)) { + if (!(\is_bool($timeout) || \is_numeric($timeout))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($timeout) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeout) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $timeout = (int) $timeout; + } + } + $promise = timeout($promise, $timeout); + $phabelReturn = call(static function () use($promise, $default) { + try { + return (yield $promise); + } catch (TimeoutException $exception) { + return $default; + } + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Adapts any object with a done(callable $onFulfilled, callable $onRejected) or then(callable $onFulfilled, + * callable $onRejected) method to a promise usable by components depending on placeholders implementing + * \AsyncInterop\Promise. + * + * @param object $promise Object with a done() or then() method. + * + * @return Promise Promise resolved by the $thenable object. + * + * @throws \Error If the provided object does not have a then() method. + */ +function adapt($promise) +{ + if (!\is_object($promise)) { + throw new \Error("Object must be provided"); + } + $deferred = new Deferred(); + if (\method_exists($promise, 'done')) { + $promise->done([$deferred, 'resolve'], [$deferred, 'fail']); + } elseif (\method_exists($promise, 'then')) { + $promise->then([$deferred, 'resolve'], [$deferred, 'fail']); + } else { + throw new \Error("Object must have a 'then' or 'done' method"); + } + $phabelReturn = $deferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Returns a promise that is resolved when all promises are resolved. The returned promise will not fail. + * Returned promise succeeds with a two-item array delineating successful and failed promise results, + * with keys identical and corresponding to the original given array. + * + * This function is the same as some() with the notable exception that it will never fail even + * if all promises in the array resolve unsuccessfully. + * + * @template TValue + * + * @param Promise[]|ReactPromise[] $promises + * + * @return Promise + * + * @throws \Error If a non-Promise is in the array. + */ +function any(array $promises) +{ + $phabelReturn = some($promises, 0); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Returns a promise that succeeds when all promises succeed, and fails if any promise fails. Returned + * promise succeeds with an array of values used to succeed each contained promise, with keys corresponding to + * the array of promises. + * + * @param Promise[]|ReactPromise[] $promises Array of only promises. + * + * @return Promise + * + * @throws \Error If a non-Promise is in the array. + * + * @template TValue + * + * @psalm-param array|ReactPromise> $promises + * @psalm-assert array|ReactPromise> $promises $promises + * @psalm-return Promise> + */ +function all(array $promises) +{ + if (empty($promises)) { + $phabelReturn = new Success([]); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $deferred = new Deferred(); + $result = $deferred->promise(); + $pending = \count($promises); + $values = []; + foreach ($promises as $key => $promise) { + if ($promise instanceof ReactPromise) { + $promise = adapt($promise); + } elseif (!$promise instanceof Promise) { + throw createTypeError([Promise::class, ReactPromise::class], $promise); + } + $values[$key] = null; + // add entry to array to preserve order + $promise->onResolve(function ($exception, $value) use(&$deferred, &$values, &$pending, $key) { + if ($pending === 0) { + return; + } + if ($exception) { + $pending = 0; + $deferred->fail($exception); + $deferred = null; + return; + } + $values[$key] = $value; + if (0 === --$pending) { + $deferred->resolve($values); + } + }); + } + $phabelReturn = $result; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Returns a promise that succeeds when the first promise succeeds, and fails only if all promises fail. + * + * @template TValue + * + * @param Promise[]|ReactPromise[] $promises Array of only promises. + * + * @return Promise + * + * @throws \Error If the array is empty or a non-Promise is in the array. + */ +function first(array $promises) +{ + if (empty($promises)) { + throw new \Error("No promises provided"); + } + $deferred = new Deferred(); + $result = $deferred->promise(); + $pending = \count($promises); + $exceptions = []; + foreach ($promises as $key => $promise) { + if ($promise instanceof ReactPromise) { + $promise = adapt($promise); + } elseif (!$promise instanceof Promise) { + throw createTypeError([Promise::class, ReactPromise::class], $promise); + } + $exceptions[$key] = null; + // add entry to array to preserve order + $promise->onResolve(function ($error, $value) use(&$deferred, &$exceptions, &$pending, $key) { + if ($pending === 0) { + return; + } + if (!$error) { + $pending = 0; + $deferred->resolve($value); + $deferred = null; + return; + } + $exceptions[$key] = $error; + if (0 === --$pending) { + $deferred->fail(new MultiReasonException($exceptions)); + } + }); + } + $phabelReturn = $result; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Resolves with a two-item array delineating successful and failed Promise results. + * + * The returned promise will only fail if the given number of required promises fail. + * + * @template TValue + * + * @param Promise[]|ReactPromise[] $promises Array of only promises. + * @param int $required Number of promises that must succeed for the + * returned promise to succeed. + * + * @return Promise + * + * @throws \Error If a non-Promise is in the array. + */ +function some(array $promises, $required = 1) +{ + if (!\is_int($required)) { + if (!(\is_bool($required) || \is_numeric($required))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($required) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($required) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $required = (int) $required; + } + } + if ($required < 0) { + throw new \Error("Number of promises required must be non-negative"); + } + $pending = \count($promises); + if ($required > $pending) { + throw new \Error("Too few promises provided"); + } + if (empty($promises)) { + $phabelReturn = new Success([[], []]); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $deferred = new Deferred(); + $result = $deferred->promise(); + $values = []; + $exceptions = []; + foreach ($promises as $key => $promise) { + if ($promise instanceof ReactPromise) { + $promise = adapt($promise); + } elseif (!$promise instanceof Promise) { + throw createTypeError([Promise::class, ReactPromise::class], $promise); + } + $values[$key] = $exceptions[$key] = null; + // add entry to arrays to preserve order + $promise->onResolve(static function ($exception, $value) use(&$values, &$exceptions, &$pending, $key, $required, $deferred) { + if ($exception) { + $exceptions[$key] = $exception; + unset($values[$key]); + } else { + $values[$key] = $value; + unset($exceptions[$key]); + } + if (0 === --$pending) { + if (\count($values) < $required) { + $deferred->fail(new MultiReasonException($exceptions)); + } else { + $deferred->resolve([$exceptions, $values]); + } + } + }); + } + $phabelReturn = $result; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Wraps a promise into another promise, altering the exception or result. + * + * @param Promise|ReactPromise $promise + * @param callable $callback + * + * @return Promise + */ +function wrap($promise, callable $callback) +{ + if ($promise instanceof ReactPromise) { + $promise = adapt($promise); + } elseif (!$promise instanceof Promise) { + throw createTypeError([Promise::class, ReactPromise::class], $promise); + } + $deferred = new Deferred(); + $promise->onResolve(static function (\Throwable $exception = null, $result) use($deferred, $callback) { + try { + $result = $callback($exception, $result); + } catch (\Exception $exception) { + $deferred->fail($exception); + return; + } catch (\Error $exception) { + $deferred->fail($exception); + return; + } + $deferred->resolve($result); + }); + $phabelReturn = $deferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +namespace Phabel\Amp\Iterator; + +use Phabel\Amp\Delayed; +use Phabel\Amp\Emitter; +use Phabel\Amp\Iterator; +use Phabel\Amp\Producer; +use Phabel\Amp\Promise; +use function Phabel\Amp\call; +use function Phabel\Amp\coroutine; +use function Phabel\Amp\Internal\createTypeError; +/** + * Creates an iterator from the given iterable, emitting the each value. The iterable may contain promises. If any + * promise fails, the iterator will fail with the same reason. + * + * @param array|\Traversable $iterable Elements to emit. + * @param int $delay Delay between element emissions in milliseconds. + * + * @return Iterator + * + * @throws \TypeError If the argument is not an array or instance of \Traversable. + */ +function fromIterable($iterable, $delay = 0) +{ + if (!\is_int($delay)) { + if (!(\is_bool($delay) || \is_numeric($delay))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($delay) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($delay) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $delay = (int) $delay; + } + } + if (!$iterable instanceof \Traversable && !\is_array($iterable)) { + throw createTypeError(["array", "Traversable"], $iterable); + } + if ($delay) { + $phabelReturn = new Producer(static function (callable $emit) use($iterable, $delay) { + foreach ($iterable as $value) { + (yield new Delayed($delay)); + (yield $emit($value)); + } + }); + if (!$phabelReturn instanceof Iterator) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Iterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = new Producer(static function (callable $emit) use($iterable) { + foreach ($iterable as $value) { + (yield $emit($value)); + } + }); + if (!$phabelReturn instanceof Iterator) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Iterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * @template TValue + * @template TReturn + * + * @param Iterator $iterator + * @param callable (TValue $value): TReturn $onEmit + * + * @return Iterator + */ +function map(Iterator $iterator, callable $onEmit) +{ + $phabelReturn = new Producer(static function (callable $emit) use($iterator, $onEmit) { + while ((yield $iterator->advance())) { + (yield $emit($onEmit($iterator->getCurrent()))); + } + }); + if (!$phabelReturn instanceof Iterator) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Iterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * @template TValue + * + * @param Iterator $iterator + * @param callable(TValue $value):bool $filter + * + * @return Iterator + */ +function filter(Iterator $iterator, callable $filter) +{ + $phabelReturn = new Producer(static function (callable $emit) use($iterator, $filter) { + while ((yield $iterator->advance())) { + if ($filter($iterator->getCurrent())) { + (yield $emit($iterator->getCurrent())); + } + } + }); + if (!$phabelReturn instanceof Iterator) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Iterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Creates an iterator that emits values emitted from any iterator in the array of iterators. + * + * @param Iterator[] $iterators + * + * @return Iterator + */ +function merge(array $iterators) +{ + $emitter = new Emitter(); + $result = $emitter->iterate(); + $coroutine = coroutine(static function (Iterator $iterator) use(&$emitter) { + while ((yield $iterator->advance()) && $emitter !== null) { + (yield $emitter->emit($iterator->getCurrent())); + } + }); + $coroutines = []; + foreach ($iterators as $iterator) { + if (!$iterator instanceof Iterator) { + throw createTypeError([Iterator::class], $iterator); + } + $coroutines[] = $coroutine($iterator); + } + Promise\all($coroutines)->onResolve(static function ($exception) use(&$emitter) { + if ($exception) { + $emitter->fail($exception); + $emitter = null; + } else { + $emitter->complete(); + } + }); + $phabelReturn = $result; + if (!$phabelReturn instanceof Iterator) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Iterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Concatenates the given iterators into a single iterator, emitting values from a single iterator at a time. The + * prior iterator must complete before values are emitted from any subsequent iterators. Iterators are concatenated + * in the order given (iteration order of the array). + * + * @param Iterator[] $iterators + * + * @return Iterator + */ +function concat(array $iterators) +{ + foreach ($iterators as $iterator) { + if (!$iterator instanceof Iterator) { + throw createTypeError([Iterator::class], $iterator); + } + } + $emitter = new Emitter(); + $previous = []; + $promise = Promise\all($previous); + $coroutine = coroutine(static function (Iterator $iterator, callable $emit) { + while ((yield $iterator->advance())) { + (yield $emit($iterator->getCurrent())); + } + }); + foreach ($iterators as $iterator) { + $emit = coroutine(static function ($value) use($emitter, $promise) { + static $pending = \true, $failed = \false; + if ($failed) { + return; + } + if ($pending) { + try { + (yield $promise); + $pending = \false; + } catch (\Exception $exception) { + $failed = \true; + return; + // Prior iterator failed. + } catch (\Error $exception) { + $failed = \true; + return; + // Prior iterator failed. + } + } + (yield $emitter->emit($value)); + }); + $previous[] = $coroutine($iterator, $emit); + $promise = Promise\all($previous); + } + $promise->onResolve(static function ($exception) use($emitter) { + if ($exception) { + $emitter->fail($exception); + return; + } + $emitter->complete(); + }); + $phabelReturn = $emitter->iterate(); + if (!$phabelReturn instanceof Iterator) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Iterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Discards all remaining items and returns the number of discarded items. + * + * @template TValue + * + * @param Iterator $iterator + * + * @return Promise + * + * @psalm-param Iterator $iterator + * @psalm-return Promise + */ +function discard(Iterator $iterator) +{ + $phabelReturn = call(static function () use($iterator) { + $count = 0; + while ((yield $iterator->advance())) { + $count++; + } + return $count; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Collects all items from an iterator into an array. + * + * @template TValue + * + * @param Iterator $iterator + * + * @psalm-param Iterator $iterator + * + * @return Promise + * @psalm-return Promise> + */ +function toArray(Iterator $iterator) +{ + $phabelReturn = call(static function () use($iterator) { + /** @psalm-var list $array */ + $array = []; + while ((yield $iterator->advance())) { + $array[] = $iterator->getCurrent(); + } + return $array; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} diff --git a/vendor-bundle/amphp/amp/psalm.examples.xml b/vendor-bundle/amphp/amp/psalm.examples.xml new file mode 100644 index 000000000..6871fdf92 --- /dev/null +++ b/vendor-bundle/amphp/amp/psalm.examples.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/vendor-bundle/amphp/amp/psalm.xml b/vendor-bundle/amphp/amp/psalm.xml new file mode 100644 index 000000000..ad5dd774f --- /dev/null +++ b/vendor-bundle/amphp/amp/psalm.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor-bundle/amphp/byte-stream/lib/Base64/Base64DecodingInputStream.php b/vendor-bundle/amphp/byte-stream/lib/Base64/Base64DecodingInputStream.php new file mode 100644 index 000000000..de30a1e9e --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/Base64/Base64DecodingInputStream.php @@ -0,0 +1,55 @@ +source = $source; + } + public function read() + { + $phabelReturn = call(function () { + if ($this->source === null) { + throw new StreamException('Failed to read stream chunk due to invalid base64 data'); + } + $chunk = (yield $this->source->read()); + if ($chunk === null) { + if ($this->buffer === null) { + return null; + } + $chunk = \base64_decode($this->buffer, \true); + if ($chunk === \false) { + $this->source = null; + $this->buffer = null; + throw new StreamException('Failed to read stream chunk due to invalid base64 data'); + } + $this->buffer = null; + return $chunk; + } + $this->buffer .= $chunk; + $length = \strlen($this->buffer); + $chunk = \base64_decode(\substr($this->buffer, 0, $length - $length % 4), \true); + if ($chunk === \false) { + $this->source = null; + $this->buffer = null; + throw new StreamException('Failed to read stream chunk due to invalid base64 data'); + } + $this->buffer = \substr($this->buffer, $length - $length % 4); + return $chunk; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/Base64/Base64DecodingOutputStream.php b/vendor-bundle/amphp/byte-stream/lib/Base64/Base64DecodingOutputStream.php new file mode 100644 index 000000000..8247439d1 --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/Base64/Base64DecodingOutputStream.php @@ -0,0 +1,73 @@ +destination = $destination; + } + public function write($data) + { + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $data = (string) $data; + } + } + $this->buffer .= $data; + $length = \strlen($this->buffer); + $chunk = \base64_decode(\substr($this->buffer, 0, $length - $length % 4), \true); + if ($chunk === \false) { + $phabelReturn = new Failure(new StreamException('Invalid base64 near offset ' . $this->offset)); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $this->offset += $length - $length % 4; + $this->buffer = \substr($this->buffer, $length - $length % 4); + $phabelReturn = $this->destination->write($chunk); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function end($finalData = "") + { + if (!\is_string($finalData)) { + if (!(\is_string($finalData) || \is_object($finalData) && \method_exists($finalData, '__toString') || (\is_bool($finalData) || \is_numeric($finalData)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($finalData) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($finalData) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $finalData = (string) $finalData; + } + } + $this->offset += \strlen($this->buffer); + $chunk = \base64_decode($this->buffer . $finalData, \true); + if ($chunk === \false) { + $phabelReturn = new Failure(new StreamException('Invalid base64 near offset ' . $this->offset)); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $this->buffer = ''; + $phabelReturn = $this->destination->end($chunk); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/Base64/Base64EncodingInputStream.php b/vendor-bundle/amphp/byte-stream/lib/Base64/Base64EncodingInputStream.php new file mode 100644 index 000000000..5cc87e895 --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/Base64/Base64EncodingInputStream.php @@ -0,0 +1,41 @@ +source = $source; + } + public function read() + { + $phabelReturn = call(function () { + $chunk = (yield $this->source->read()); + if ($chunk === null) { + if ($this->buffer === null) { + return null; + } + $chunk = \base64_encode($this->buffer); + $this->buffer = null; + return $chunk; + } + $this->buffer .= $chunk; + $length = \strlen($this->buffer); + $chunk = \base64_encode(\substr($this->buffer, 0, $length - $length % 3)); + $this->buffer = \substr($this->buffer, $length - $length % 3); + return $chunk; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/Base64/Base64EncodingOutputStream.php b/vendor-bundle/amphp/byte-stream/lib/Base64/Base64EncodingOutputStream.php new file mode 100644 index 000000000..18d5493ca --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/Base64/Base64EncodingOutputStream.php @@ -0,0 +1,53 @@ +destination = $destination; + } + public function write($data) + { + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $data = (string) $data; + } + } + $this->buffer .= $data; + $length = \strlen($this->buffer); + $chunk = \base64_encode(\substr($this->buffer, 0, $length - $length % 3)); + $this->buffer = \substr($this->buffer, $length - $length % 3); + $phabelReturn = $this->destination->write($chunk); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function end($finalData = "") + { + if (!\is_string($finalData)) { + if (!(\is_string($finalData) || \is_object($finalData) && \method_exists($finalData, '__toString') || (\is_bool($finalData) || \is_numeric($finalData)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($finalData) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($finalData) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $finalData = (string) $finalData; + } + } + $chunk = \base64_encode($this->buffer . $finalData); + $this->buffer = ''; + $phabelReturn = $this->destination->end($chunk); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/ClosedException.php b/vendor-bundle/amphp/byte-stream/lib/ClosedException.php new file mode 100644 index 000000000..1fb7adc4c --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/ClosedException.php @@ -0,0 +1,7 @@ +contents = $contents; + } + /** + * Reads data from the stream. + * + * @return Promise Resolves with the full contents or `null` if the stream has closed / already been consumed. + */ + public function read() + { + if ($this->contents === null) { + $phabelReturn = new Success(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $promise = new Success($this->contents); + $this->contents = null; + $phabelReturn = $promise; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/InputStream.php b/vendor-bundle/amphp/byte-stream/lib/InputStream.php new file mode 100644 index 000000000..a48caa3fe --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/InputStream.php @@ -0,0 +1,37 @@ +read()) !== null) { + * $buffer .= $chunk; + * } + * + * return $buffer; + * }); + * } + * ``` + */ +interface InputStream +{ + /** + * Reads data from the stream. + * + * @return Promise Resolves with a string when new data is available or `null` if the stream has closed. + * + * @psalm-return Promise + * + * @throws PendingReadError Thrown if another read operation is still pending. + */ + public function read(); +} diff --git a/vendor-bundle/amphp/byte-stream/lib/InputStreamChain.php b/vendor-bundle/amphp/byte-stream/lib/InputStreamChain.php new file mode 100644 index 000000000..12693a5db --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/InputStreamChain.php @@ -0,0 +1,52 @@ +streams = $streams; + } + /** @inheritDoc */ + public function read() + { + if ($this->reading) { + throw new PendingReadError(); + } + if (!$this->streams) { + $phabelReturn = new Success(null); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = call(function () { + $this->reading = \true; + try { + while ($this->streams) { + $chunk = (yield $this->streams[0]->read()); + if ($chunk === null) { + \array_shift($this->streams); + continue; + } + return $chunk; + } + return null; + } finally { + $this->reading = \false; + } + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/IteratorStream.php b/vendor-bundle/amphp/byte-stream/lib/IteratorStream.php new file mode 100644 index 000000000..b622bcbd2 --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/IteratorStream.php @@ -0,0 +1,63 @@ + */ + private $iterator; + /** @var \Throwable|null */ + private $exception; + /** @var bool */ + private $pending = \false; + /** + * @psam-param Iterator $iterator + */ + public function __construct(Iterator $iterator) + { + $this->iterator = $iterator; + } + /** @inheritdoc */ + public function read() + { + if ($this->exception) { + $phabelReturn = new Failure($this->exception); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->pending) { + throw new PendingReadError(); + } + $this->pending = \true; + /** @var Deferred $deferred */ + $deferred = new Deferred(); + $this->iterator->advance()->onResolve(function ($error, $hasNextElement) use($deferred) { + $this->pending = \false; + if ($error) { + $this->exception = $error; + $deferred->fail($error); + } elseif ($hasNextElement) { + $chunk = $this->iterator->getCurrent(); + if (!\is_string($chunk)) { + $this->exception = new StreamException(\sprintf("Unexpected iterator value of type '%s', expected string", \is_object($chunk) ? \get_class($chunk) : \gettype($chunk))); + $deferred->fail($this->exception); + return; + } + $deferred->resolve($chunk); + } else { + $deferred->resolve(); + } + }); + $phabelReturn = $deferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/LineReader.php b/vendor-bundle/amphp/byte-stream/lib/LineReader.php new file mode 100644 index 000000000..34a053e31 --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/LineReader.php @@ -0,0 +1,80 @@ +source = $inputStream; + $this->delimiter = $delimiter === null ? "\n" : $delimiter; + $this->lineMode = $delimiter === null; + } + /** + * @return Promise + */ + public function readLine() + { + $phabelReturn = call(function () { + if (\false !== \strpos($this->buffer, $this->delimiter)) { + list($line, $this->buffer) = \explode($this->delimiter, $this->buffer, 2); + return $this->lineMode ? \rtrim($line, "\r") : $line; + } + while (null !== ($chunk = (yield $this->source->read()))) { + $this->buffer .= $chunk; + if (\false !== \strpos($this->buffer, $this->delimiter)) { + list($line, $this->buffer) = \explode($this->delimiter, $this->buffer, 2); + return $this->lineMode ? \rtrim($line, "\r") : $line; + } + } + if ($this->buffer === "") { + return null; + } + $line = $this->buffer; + $this->buffer = ""; + return $this->lineMode ? \rtrim($line, "\r") : $line; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getBuffer() + { + $phabelReturn = $this->buffer; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return void + */ + public function clearBuffer() + { + $this->buffer = ""; + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/Message.php b/vendor-bundle/amphp/byte-stream/lib/Message.php new file mode 100644 index 000000000..fff91c97b --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/Message.php @@ -0,0 +1,171 @@ +read()) !== null) { + * // Immediately use $chunk, reducing memory consumption since the entire message is never buffered. + * } + * + * @deprecated Use Amp\ByteStream\Payload instead. + */ +class Message implements InputStream, Promise +{ + /** @var InputStream */ + private $source; + /** @var string */ + private $buffer = ""; + /** @var Deferred|null */ + private $pendingRead; + /** @var Coroutine|null */ + private $coroutine; + /** @var bool True if onResolve() has been called. */ + private $buffering = \false; + /** @var Deferred|null */ + private $backpressure; + /** @var bool True if the iterator has completed. */ + private $complete = \false; + /** @var \Throwable|null Used to fail future reads on failure. */ + private $error; + /** + * @param InputStream $source An iterator that only emits strings. + */ + public function __construct(InputStream $source) + { + $this->source = $source; + } + private function consume() + { + while (($chunk = (yield $this->source->read())) !== null) { + $buffer = $this->buffer .= $chunk; + if ($buffer === "") { + continue; + // Do not succeed reads with empty string. + } elseif ($this->pendingRead) { + $deferred = $this->pendingRead; + $this->pendingRead = null; + $this->buffer = ""; + $deferred->resolve($buffer); + $buffer = ""; + // Destroy last emitted chunk to free memory. + } elseif (!$this->buffering) { + $buffer = ""; + // Destroy last emitted chunk to free memory. + $this->backpressure = new Deferred(); + (yield $this->backpressure->promise()); + } + } + $this->complete = \true; + if ($this->pendingRead) { + $deferred = $this->pendingRead; + $this->pendingRead = null; + $deferred->resolve($this->buffer !== "" ? $this->buffer : null); + $this->buffer = ""; + } + return $this->buffer; + } + /** @inheritdoc */ + public final function read() + { + if ($this->pendingRead) { + throw new PendingReadError(); + } + if ($this->coroutine === null) { + $this->coroutine = new Coroutine($this->consume()); + $this->coroutine->onResolve(function ($error) { + if ($error) { + $this->error = $error; + } + if ($this->pendingRead) { + $deferred = $this->pendingRead; + $this->pendingRead = null; + $deferred->fail($error); + } + }); + } + if ($this->error) { + $phabelReturn = new Failure($this->error); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->buffer !== "") { + $buffer = $this->buffer; + $this->buffer = ""; + if ($this->backpressure) { + $backpressure = $this->backpressure; + $this->backpressure = null; + $backpressure->resolve(); + } + $phabelReturn = new Success($buffer); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->complete) { + $phabelReturn = new Success(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $this->pendingRead = new Deferred(); + $phabelReturn = $this->pendingRead->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** @inheritdoc */ + public final function onResolve(callable $onResolved) + { + $this->buffering = \true; + if ($this->coroutine === null) { + $this->coroutine = new Coroutine($this->consume()); + } + if ($this->backpressure) { + $backpressure = $this->backpressure; + $this->backpressure = null; + $backpressure->resolve(); + } + $this->coroutine->onResolve($onResolved); + } + /** + * Exposes the source input stream. + * + * This might be required to resolve a promise with an InputStream, because promises in Amp can't be resolved with + * other promises. + * + * @return InputStream + */ + public final function getInputStream() + { + $phabelReturn = $this->source; + if (!$phabelReturn instanceof InputStream) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type InputStream, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/OutputBuffer.php b/vendor-bundle/amphp/byte-stream/lib/OutputBuffer.php new file mode 100644 index 000000000..8e63443c5 --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/OutputBuffer.php @@ -0,0 +1,65 @@ +deferred = new Deferred(); + } + public function write($data) + { + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $data = (string) $data; + } + } + if ($this->closed) { + throw new ClosedException("The stream has already been closed."); + } + $this->contents .= $data; + $phabelReturn = new Success(\strlen($data)); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function end($finalData = "") + { + if (!\is_string($finalData)) { + if (!(\is_string($finalData) || \is_object($finalData) && \method_exists($finalData, '__toString') || (\is_bool($finalData) || \is_numeric($finalData)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($finalData) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($finalData) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $finalData = (string) $finalData; + } + } + if ($this->closed) { + throw new ClosedException("The stream has already been closed."); + } + $this->contents .= $finalData; + $this->closed = \true; + $this->deferred->resolve($this->contents); + $this->contents = ""; + $phabelReturn = new Success(\strlen($finalData)); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function onResolve(callable $onResolved) + { + $this->deferred->promise()->onResolve($onResolved); + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/OutputStream.php b/vendor-bundle/amphp/byte-stream/lib/OutputStream.php new file mode 100644 index 000000000..a1a4ac952 --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/OutputStream.php @@ -0,0 +1,35 @@ +stream = $stream; + } + public function __destruct() + { + if (!$this->promise) { + Promise\rethrow(new Coroutine($this->consume())); + } + } + private function consume() + { + try { + if ($this->lastRead && null === (yield $this->lastRead)) { + return; + } + while (null !== (yield $this->stream->read())) { + // Discard unread bytes from message. + } + } catch (\Exception $exception) { + // If exception is thrown here the connection closed anyway. + } catch (\Error $exception) { + // If exception is thrown here the connection closed anyway. + } + } + /** + * @inheritdoc + * + * @throws \Error If a buffered message was requested by calling buffer(). + */ + public final function read() + { + if ($this->promise) { + throw new \Error("Cannot stream message data once a buffered message has been requested"); + } + $phabelReturn = $this->lastRead = $this->stream->read(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Buffers the entire message and resolves the returned promise then. + * + * @return Promise Resolves with the entire message contents. + */ + public final function buffer() + { + if ($this->promise) { + $phabelReturn = $this->promise; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = $this->promise = call(function () { + $buffer = ''; + if ($this->lastRead && null === (yield $this->lastRead)) { + return $buffer; + } + while (null !== ($chunk = (yield $this->stream->read()))) { + $buffer .= $chunk; + } + return $buffer; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/PendingReadError.php b/vendor-bundle/amphp/byte-stream/lib/PendingReadError.php new file mode 100644 index 000000000..52fe75653 --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/PendingReadError.php @@ -0,0 +1,28 @@ +useSingleRead = $useSingleRead; + if (\strpos($meta["mode"], "r") === \false && \strpos($meta["mode"], "+") === \false) { + throw new \Error("Expected a readable stream"); + } + \stream_set_blocking($stream, \false); + \stream_set_read_buffer($stream, 0); + $this->resource =& $stream; + $this->chunkSize =& $chunkSize; + $deferred =& $this->deferred; + $readable =& $this->readable; + $this->watcher = Loop::onReadable($this->resource, static function ($watcher) use(&$deferred, &$readable, &$stream, &$chunkSize, $useSingleRead) { + if ($useSingleRead) { + $data = @\fread($stream, $chunkSize); + } else { + $data = @\stream_get_contents($stream, $chunkSize); + } + \assert($data !== \false, "Trying to read from a previously fclose()'d resource. Do NOT manually fclose() resources the loop still has a reference to."); + // Error suppression, because pthreads does crazy things with resources, + // which might be closed during two operations. + // See https://github.com/amphp/byte-stream/issues/32 + if ($data === '' && @\feof($stream)) { + $readable = \false; + $stream = null; + $data = null; + // Stream closed, resolve read with null. + Loop::cancel($watcher); + } else { + Loop::disable($watcher); + } + $temp = $deferred; + $deferred = null; + \assert($temp instanceof Deferred); + $temp->resolve($data); + }); + $this->immediateCallable = static function ($watcherId, $data) use(&$deferred) { + $temp = $deferred; + $deferred = null; + \assert($temp instanceof Deferred); + $temp->resolve($data); + }; + Loop::disable($this->watcher); + } + /** @inheritdoc */ + public function read() + { + if ($this->deferred !== null) { + throw new PendingReadError(); + } + if (!$this->readable) { + $phabelReturn = new Success(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + // Resolve with null on closed stream. + } + \assert($this->resource !== null); + // Attempt a direct read, because Windows suffers from slow I/O on STDIN otherwise. + if ($this->useSingleRead) { + $data = @\fread($this->resource, $this->chunkSize); + } else { + $data = @\stream_get_contents($this->resource, $this->chunkSize); + } + \assert($data !== \false, "Trying to read from a previously fclose()'d resource. Do NOT manually fclose() resources the loop still has a reference to."); + if ($data === '') { + // Error suppression, because pthreads does crazy things with resources, + // which might be closed during two operations. + // See https://github.com/amphp/byte-stream/issues/32 + if (@\feof($this->resource)) { + $this->readable = \false; + $this->resource = null; + Loop::cancel($this->watcher); + $phabelReturn = new Success(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + // Stream closed, resolve read with null. + } + $this->deferred = new Deferred(); + Loop::enable($this->watcher); + $phabelReturn = $this->deferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + // Prevent an immediate read → write loop from blocking everything + // See e.g. examples/benchmark-throughput.php + $this->deferred = new Deferred(); + $this->immediateWatcher = Loop::defer($this->immediateCallable, $data); + $phabelReturn = $this->deferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Closes the stream forcefully. Multiple `close()` calls are ignored. + * + * @return void + */ + public function close() + { + if (\is_resource($this->resource)) { + // Error suppression, as resource might already be closed + $meta = @\stream_get_meta_data($this->resource); + if ($meta && \strpos($meta["mode"], "+") !== \false) { + @\stream_socket_shutdown($this->resource, \STREAM_SHUT_RD); + } else { + /** @psalm-suppress InvalidPropertyAssignmentValue */ + @\fclose($this->resource); + } + } + $this->free(); + } + /** + * Nulls reference to resource, marks stream unreadable, and succeeds any pending read with null. + * + * @return void + */ + private function free() + { + $this->readable = \false; + $this->resource = null; + if ($this->deferred !== null) { + $deferred = $this->deferred; + $this->deferred = null; + $deferred->resolve(); + } + Loop::cancel($this->watcher); + if ($this->immediateWatcher !== null) { + Loop::cancel($this->immediateWatcher); + } + } + /** + * @return resource|null The stream resource or null if the stream has closed. + */ + public function getResource() + { + return $this->resource; + } + /** + * @return void + */ + public function setChunkSize($chunkSize) + { + if (!\is_int($chunkSize)) { + if (!(\is_bool($chunkSize) || \is_numeric($chunkSize))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($chunkSize) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($chunkSize) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $chunkSize = (int) $chunkSize; + } + } + $this->chunkSize = $chunkSize; + } + /** + * References the read watcher, so the loop keeps running in case there's an active read. + * + * @return void + * + * @see Loop::reference() + */ + public function reference() + { + if (!$this->resource) { + throw new \Error("Resource has already been freed"); + } + Loop::reference($this->watcher); + } + /** + * Unreferences the read watcher, so the loop doesn't keep running even if there are active reads. + * + * @return void + * + * @see Loop::unreference() + */ + public function unreference() + { + if (!$this->resource) { + throw new \Error("Resource has already been freed"); + } + Loop::unreference($this->watcher); + } + public function __destruct() + { + if ($this->resource !== null) { + $this->free(); + } + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/ResourceOutputStream.php b/vendor-bundle/amphp/byte-stream/lib/ResourceOutputStream.php new file mode 100644 index 000000000..d6ccbe469 --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/ResourceOutputStream.php @@ -0,0 +1,356 @@ + */ + private $writes; + /** @var bool */ + private $writable = \true; + /** @var int|null */ + private $chunkSize; + /** + * @param resource $stream Stream resource. + * @param int|null $chunkSize Chunk size per `fwrite()` operation. + */ + public function __construct($stream, $chunkSize = null) + { + if (!\is_null($chunkSize)) { + if (!\is_int($chunkSize)) { + if (!(\is_bool($chunkSize) || \is_numeric($chunkSize))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($chunkSize) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($chunkSize) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $chunkSize = (int) $chunkSize; + } + } + } + if (!\is_resource($stream) || \get_resource_type($stream) !== 'stream') { + throw new \Error("Expected a valid stream"); + } + $meta = \stream_get_meta_data($stream); + if (\strpos($meta["mode"], "r") !== \false && \strpos($meta["mode"], "+") === \false) { + throw new \Error("Expected a writable stream"); + } + \stream_set_blocking($stream, \false); + \stream_set_write_buffer($stream, 0); + $this->resource = $stream; + $this->chunkSize =& $chunkSize; + $writes = $this->writes = new \SplQueue(); + $writable =& $this->writable; + $resource =& $this->resource; + $this->watcher = Loop::onWritable($stream, static function ($watcher, $stream) use($writes, &$chunkSize, &$writable, &$resource) { + static $emptyWrites = 0; + try { + while (!$writes->isEmpty()) { + /** @var Deferred $deferred */ + list($data, $previous, $deferred) = $writes->shift(); + $length = \strlen($data); + if ($length === 0) { + $deferred->resolve(0); + continue; + } + if (!\is_resource($stream) || ($metaData = @\stream_get_meta_data($stream)) && $metaData['eof']) { + throw new ClosedException("The stream was closed by the peer"); + } + // Error reporting suppressed since fwrite() emits E_WARNING if the pipe is broken or the buffer is full. + // Use conditional, because PHP doesn't like getting null passed + if ($chunkSize) { + $written = @\fwrite($stream, $data, $chunkSize); + } else { + $written = @\fwrite($stream, $data); + } + \assert( + $written !== \false || \PHP_VERSION_ID >= 70400, + // PHP 7.4+ returns false on EPIPE. + "Trying to write on a previously fclose()'d resource. Do NOT manually fclose() resources the still referenced in the loop." + ); + // PHP 7.4.0 and 7.4.1 may return false on EAGAIN. + if ($written === \false && \PHP_VERSION_ID >= 70402) { + $message = "Failed to write to stream"; + if ($error = \error_get_last()) { + $message .= \sprintf("; %s", $error["message"]); + } + throw new StreamException($message); + } + // Broken pipes between processes on macOS/FreeBSD do not detect EOF properly. + if ($written === 0 || $written === \false) { + if ($emptyWrites++ > self::MAX_CONSECUTIVE_EMPTY_WRITES) { + $message = "Failed to write to stream after multiple attempts"; + if ($error = \error_get_last()) { + $message .= \sprintf("; %s", $error["message"]); + } + throw new StreamException($message); + } + $writes->unshift([$data, $previous, $deferred]); + return; + } + $emptyWrites = 0; + if ($length > $written) { + $data = \substr($data, $written); + $writes->unshift([$data, $written + $previous, $deferred]); + return; + } + $deferred->resolve($written + $previous); + } + } catch (\Exception $exception) { + $resource = null; + $writable = \false; + /** @psalm-suppress PossiblyUndefinedVariable */ + $deferred->fail($exception); + while (!$writes->isEmpty()) { + list(, , $deferred) = $writes->shift(); + $deferred->fail($exception); + } + Loop::cancel($watcher); + } catch (\Error $exception) { + $resource = null; + $writable = \false; + /** @psalm-suppress PossiblyUndefinedVariable */ + $deferred->fail($exception); + while (!$writes->isEmpty()) { + list(, , $deferred) = $writes->shift(); + $deferred->fail($exception); + } + Loop::cancel($watcher); + } finally { + if ($writes->isEmpty()) { + Loop::disable($watcher); + } + } + }); + Loop::disable($this->watcher); + } + /** + * Writes data to the stream. + * + * @param string $data Bytes to write. + * + * @return Promise Succeeds once the data has been successfully written to the stream. + * + * @throws ClosedException If the stream has already been closed. + */ + public function write($data) + { + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $data = (string) $data; + } + } + $phabelReturn = $this->send($data, \false); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Closes the stream after all pending writes have been completed. Optionally writes a final data chunk before. + * + * @param string $finalData Bytes to write. + * + * @return Promise Succeeds once the data has been successfully written to the stream. + * + * @throws ClosedException If the stream has already been closed. + */ + public function end($finalData = "") + { + if (!\is_string($finalData)) { + if (!(\is_string($finalData) || \is_object($finalData) && \method_exists($finalData, '__toString') || (\is_bool($finalData) || \is_numeric($finalData)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($finalData) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($finalData) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $finalData = (string) $finalData; + } + } + $phabelReturn = $this->send($finalData, \true); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function send($data, $end = \false) + { + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $data = (string) $data; + } + } + if (!\is_bool($end)) { + if (!(\is_bool($end) || \is_numeric($end) || \is_string($end))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($end) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($end) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $end = (bool) $end; + } + } + if (!$this->writable) { + $phabelReturn = new Failure(new ClosedException("The stream is not writable")); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $length = \strlen($data); + $written = 0; + if ($end) { + $this->writable = \false; + } + if ($this->writes->isEmpty()) { + if ($length === 0) { + if ($end) { + $this->close(); + } + $phabelReturn = new Success(0); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if (!\is_resource($this->resource) || ($metaData = @\stream_get_meta_data($this->resource)) && $metaData['eof']) { + $phabelReturn = new Failure(new ClosedException("The stream was closed by the peer")); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + // Error reporting suppressed since fwrite() emits E_WARNING if the pipe is broken or the buffer is full. + // Use conditional, because PHP doesn't like getting null passed. + if ($this->chunkSize) { + $written = @\fwrite($this->resource, $data, $this->chunkSize); + } else { + $written = @\fwrite($this->resource, $data); + } + \assert( + $written !== \false || \PHP_VERSION_ID >= 70400, + // PHP 7.4+ returns false on EPIPE. + "Trying to write on a previously fclose()'d resource. Do NOT manually fclose() resources the still referenced in the loop." + ); + // PHP 7.4.0 and 7.4.1 may return false on EAGAIN. + if ($written === \false && \PHP_VERSION_ID >= 70402) { + $message = "Failed to write to stream"; + if ($error = \error_get_last()) { + $message .= \sprintf("; %s", $error["message"]); + } + $phabelReturn = new Failure(new StreamException($message)); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $written = (int) $written; + // Cast potential false to 0. + if ($length === $written) { + if ($end) { + $this->close(); + } + $phabelReturn = new Success($written); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $data = \substr($data, $written); + } + $deferred = new Deferred(); + if ($length - $written > self::LARGE_CHUNK_SIZE) { + $chunks = \str_split($data, self::LARGE_CHUNK_SIZE); + $data = \array_pop($chunks); + foreach ($chunks as $chunk) { + $this->writes->push([$chunk, $written, new Deferred()]); + $written += self::LARGE_CHUNK_SIZE; + } + } + $this->writes->push([$data, $written, $deferred]); + Loop::enable($this->watcher); + $promise = $deferred->promise(); + if ($end) { + $promise->onResolve([$this, "close"]); + } + $phabelReturn = $promise; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Closes the stream forcefully. Multiple `close()` calls are ignored. + * + * @return void + */ + public function close() + { + if (\is_resource($this->resource)) { + // Error suppression, as resource might already be closed + $meta = @\stream_get_meta_data($this->resource); + if ($meta && \strpos($meta["mode"], "+") !== \false) { + @\stream_socket_shutdown($this->resource, \STREAM_SHUT_WR); + } else { + /** @psalm-suppress InvalidPropertyAssignmentValue psalm reports this as closed-resource */ + @\fclose($this->resource); + } + } + $this->free(); + } + /** + * Nulls reference to resource, marks stream unwritable, and fails any pending write. + * + * @return void + */ + private function free() + { + $this->resource = null; + $this->writable = \false; + if (!$this->writes->isEmpty()) { + $exception = new ClosedException("The socket was closed before writing completed"); + do { + /** @var Deferred $deferred */ + list(, , $deferred) = $this->writes->shift(); + $deferred->fail($exception); + } while (!$this->writes->isEmpty()); + } + Loop::cancel($this->watcher); + } + /** + * @return resource|null Stream resource or null if end() has been called or the stream closed. + */ + public function getResource() + { + return $this->resource; + } + /** + * @return void + */ + public function setChunkSize($chunkSize) + { + if (!\is_int($chunkSize)) { + if (!(\is_bool($chunkSize) || \is_numeric($chunkSize))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($chunkSize) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($chunkSize) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $chunkSize = (int) $chunkSize; + } + } + $this->chunkSize = $chunkSize; + } + public function __destruct() + { + if ($this->resource !== null) { + $this->free(); + } + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/StreamException.php b/vendor-bundle/amphp/byte-stream/lib/StreamException.php new file mode 100644 index 000000000..204e5ad6a --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/StreamException.php @@ -0,0 +1,7 @@ +source = $source; + $this->encoding = $encoding; + $this->options = $options; + $this->resource = @\inflate_init($encoding, $options); + if ($this->resource === \false) { + throw new StreamException("Failed initializing deflate context"); + } + } + /** @inheritdoc */ + public function read() + { + $phabelReturn = call(function () { + if ($this->resource === null) { + return null; + } + \assert($this->source !== null); + $data = (yield $this->source->read()); + // Needs a double guard, as stream might have been closed while reading + /** @psalm-suppress ParadoxicalCondition */ + if ($this->resource === null) { + return null; + } + if ($data === null) { + $decompressed = @\inflate_add($this->resource, "", \ZLIB_FINISH); + if ($decompressed === \false) { + throw new StreamException("Failed adding data to deflate context"); + } + $this->close(); + return $decompressed; + } + $decompressed = @\inflate_add($this->resource, $data, \ZLIB_SYNC_FLUSH); + if ($decompressed === \false) { + throw new StreamException("Failed adding data to deflate context"); + } + return $decompressed; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @internal + * @return void + */ + private function close() + { + $this->resource = null; + $this->source = null; + } + /** + * Gets the used compression encoding. + * + * @return int Encoding specified on construction time. + */ + public function getEncoding() + { + $phabelReturn = $this->encoding; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the used compression options. + * + * @return array Options array passed on construction time. + */ + public function getOptions() + { + $phabelReturn = $this->options; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/ZlibOutputStream.php b/vendor-bundle/amphp/byte-stream/lib/ZlibOutputStream.php new file mode 100644 index 000000000..856455e70 --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/ZlibOutputStream.php @@ -0,0 +1,142 @@ +destination = $destination; + $this->encoding = $encoding; + $this->options = $options; + $this->resource = @\deflate_init($encoding, $options); + if ($this->resource === \false) { + throw new StreamException("Failed initializing deflate context"); + } + } + /** @inheritdoc */ + public function write($data) + { + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $data = (string) $data; + } + } + if ($this->resource === null) { + throw new ClosedException("The stream has already been closed"); + } + \assert($this->destination !== null); + $compressed = \deflate_add($this->resource, $data, \ZLIB_SYNC_FLUSH); + if ($compressed === \false) { + throw new StreamException("Failed adding data to deflate context"); + } + $promise = $this->destination->write($compressed); + $promise->onResolve(function ($error) { + if ($error) { + $this->close(); + } + }); + $phabelReturn = $promise; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** @inheritdoc */ + public function end($finalData = "") + { + if (!\is_string($finalData)) { + if (!(\is_string($finalData) || \is_object($finalData) && \method_exists($finalData, '__toString') || (\is_bool($finalData) || \is_numeric($finalData)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($finalData) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($finalData) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $finalData = (string) $finalData; + } + } + if ($this->resource === null) { + throw new ClosedException("The stream has already been closed"); + } + \assert($this->destination !== null); + $compressed = \deflate_add($this->resource, $finalData, \ZLIB_FINISH); + if ($compressed === \false) { + throw new StreamException("Failed adding data to deflate context"); + } + $promise = $this->destination->end($compressed); + $promise->onResolve(function () { + $this->close(); + }); + $phabelReturn = $promise; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @internal + * @return void + */ + private function close() + { + $this->resource = null; + $this->destination = null; + } + /** + * Gets the used compression encoding. + * + * @return int Encoding specified on construction time. + */ + public function getEncoding() + { + $phabelReturn = $this->encoding; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the used compression options. + * + * @return array Options array passed on construction time. + */ + public function getOptions() + { + $phabelReturn = $this->options; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/byte-stream/lib/functions.php b/vendor-bundle/amphp/byte-stream/lib/functions.php new file mode 100644 index 000000000..dfb874fdd --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/lib/functions.php @@ -0,0 +1,207 @@ +read())) !== null) { + $written += \strlen($chunk); + $writePromise = $destination->write($chunk); + $chunk = null; + // free memory + (yield $writePromise); + } + return $written; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * @param \Amp\ByteStream\InputStream $source + * + * @return \Amp\Promise + */ +function buffer(InputStream $source) +{ + $phabelReturn = call(function () use($source) { + $buffer = ""; + while (($chunk = (yield $source->read())) !== null) { + $buffer .= $chunk; + $chunk = null; + // free memory + } + return $buffer; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * The php://input input buffer stream for the process associated with the currently active event loop. + * + * @return ResourceInputStream + */ +function getInputBufferStream() +{ + static $key = InputStream::class . '\\input'; + $stream = Loop::getState($key); + if (!$stream) { + $stream = new ResourceInputStream(\fopen('php://input', 'rb')); + Loop::setState($key, $stream); + } + $phabelReturn = $stream; + if (!$phabelReturn instanceof ResourceInputStream) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ResourceInputStream, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * The php://output output buffer stream for the process associated with the currently active event loop. + * + * @return ResourceOutputStream + */ +function getOutputBufferStream() +{ + static $key = OutputStream::class . '\\output'; + $stream = Loop::getState($key); + if (!$stream) { + $stream = new ResourceOutputStream(\fopen('php://output', 'wb')); + Loop::setState($key, $stream); + } + $phabelReturn = $stream; + if (!$phabelReturn instanceof ResourceOutputStream) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ResourceOutputStream, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * The STDIN stream for the process associated with the currently active event loop. + * + * @return ResourceInputStream + */ +function getStdin() +{ + static $key = InputStream::class . '\\stdin'; + $stream = Loop::getState($key); + if (!$stream) { + $stream = new ResourceInputStream(\STDIN); + Loop::setState($key, $stream); + } + $phabelReturn = $stream; + if (!$phabelReturn instanceof ResourceInputStream) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ResourceInputStream, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * The STDOUT stream for the process associated with the currently active event loop. + * + * @return ResourceOutputStream + */ +function getStdout() +{ + static $key = OutputStream::class . '\\stdout'; + $stream = Loop::getState($key); + if (!$stream) { + $stream = new ResourceOutputStream(\STDOUT); + Loop::setState($key, $stream); + } + $phabelReturn = $stream; + if (!$phabelReturn instanceof ResourceOutputStream) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ResourceOutputStream, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * The STDERR stream for the process associated with the currently active event loop. + * + * @return ResourceOutputStream + */ +function getStderr() +{ + static $key = OutputStream::class . '\\stderr'; + $stream = Loop::getState($key); + if (!$stream) { + $stream = new ResourceOutputStream(\STDERR); + Loop::setState($key, $stream); + } + $phabelReturn = $stream; + if (!$phabelReturn instanceof ResourceOutputStream) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ResourceOutputStream, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +function parseLineDelimitedJson(InputStream $stream, $assoc = \false, $depth = 512, $options = 0) +{ + if (!\is_bool($assoc)) { + if (!(\is_bool($assoc) || \is_numeric($assoc) || \is_string($assoc))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($assoc) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($assoc) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $assoc = (bool) $assoc; + } + } + if (!\is_int($depth)) { + if (!(\is_bool($depth) || \is_numeric($depth))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($depth) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($depth) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $depth = (int) $depth; + } + } + if (!\is_int($options)) { + if (!(\is_bool($options) || \is_numeric($options))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($options) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($options) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $options = (int) $options; + } + } + $phabelReturn = new Producer(static function (callable $emit) use($stream, $assoc, $depth, $options) { + $reader = new LineReader($stream); + while (null !== ($line = (yield $reader->readLine()))) { + $line = \trim($line); + if ($line === '') { + continue; + } + /** @noinspection PhpComposerExtensionStubsInspection */ + $data = \json_decode($line, $assoc, $depth, $options); + /** @noinspection PhpComposerExtensionStubsInspection */ + $error = \json_last_error(); + /** @noinspection PhpComposerExtensionStubsInspection */ + if ($error !== \JSON_ERROR_NONE) { + /** @noinspection PhpComposerExtensionStubsInspection */ + throw new StreamException('Failed to parse JSON: ' . \json_last_error_msg(), $error); + } + (yield $emit($data)); + } + }); + if (!$phabelReturn instanceof Iterator) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Iterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} diff --git a/vendor-bundle/amphp/byte-stream/psalm.xml b/vendor-bundle/amphp/byte-stream/psalm.xml new file mode 100644 index 000000000..9684f55df --- /dev/null +++ b/vendor-bundle/amphp/byte-stream/psalm.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor-bundle/amphp/parallel/Vagrantfile b/vendor-bundle/amphp/parallel/Vagrantfile new file mode 100644 index 000000000..3fd791ee4 --- /dev/null +++ b/vendor-bundle/amphp/parallel/Vagrantfile @@ -0,0 +1,17 @@ +Vagrant.configure(2) do |config| + config.vm.box = "rasmus/php7dev" + + config.vm.provision "shell", inline: <<-SHELL + newphp 7 zts + + # Install pthreads from master + git clone https://github.com/krakjoe/pthreads + cd pthreads + git checkout master + phpize + ./configure + make + sudo make install + echo 'extension=pthreads.so' >> `php -i | grep php-cli.ini | awk '{print $5}'` + SHELL +end diff --git a/vendor-bundle/amphp/parallel/appveyor.yml b/vendor-bundle/amphp/parallel/appveyor.yml new file mode 100644 index 000000000..65ee88fe2 --- /dev/null +++ b/vendor-bundle/amphp/parallel/appveyor.yml @@ -0,0 +1,41 @@ +build: false +shallow_clone: false + +platform: + - x86 + - x64 + +clone_folder: c:\Phabel\projects\amphp + +cache: + - c:\Phabel\tools\php73 -> appveyor.yml + +init: + - SET PATH=C:\Program Phabel\Files\OpenSSL;c:\Phabel\tools\php73;%PATH% + - SET COMPOSER_NO_INTERACTION=1 + - SET PHP=1 + - SET ANSICON=121x90 (121x90) + +install: + - IF EXIST c:\Phabel\tools\php73 (SET PHP=0) + - IF %PHP%==1 sc config wuauserv start= auto + - IF %PHP%==1 net start wuauserv + - IF %PHP%==1 cinst -y OpenSSL.Light + - IF %PHP%==1 cinst -y php + - cd c:\Phabel\tools\php73 + - IF %PHP%==1 copy php.ini-production php.ini /Y + - IF %PHP%==1 echo date.timezone="UTC" >> php.ini + - IF %PHP%==1 echo extension_dir=ext >> php.ini + - IF %PHP%==1 echo extension=php_openssl.dll >> php.ini + - IF %PHP%==1 echo extension=php_mbstring.dll >> php.ini + - IF %PHP%==1 echo extension=php_fileinfo.dll >> php.ini + - cd c:\Phabel\projects\amphp + - appveyor DownloadFile https://getcomposer.org/composer.phar + - php composer.phar install --prefer-dist --no-progress + +test_script: + - cd c:\Phabel\projects\amphp + - phpdbg -qrr vendor/phpunit/phpunit/phpunit --colors=always --coverage-text --coverage-clover build/logs/clover.xml + # Disable for now, because it can't be combined and files can't be shown on coveralls.io + # https://github.com/php-coveralls/php-coveralls/issues/234 + # - vendor/bin/coveralls -v diff --git a/vendor-bundle/amphp/parallel/docs/Gemfile b/vendor-bundle/amphp/parallel/docs/Gemfile new file mode 100644 index 000000000..ada6383b0 --- /dev/null +++ b/vendor-bundle/amphp/parallel/docs/Gemfile @@ -0,0 +1,5 @@ +source "https://rubygems.org" +gem "github-pages" +gem "kramdown" +gem "jekyll-github-metadata" +gem "jekyll-relative-links" diff --git a/vendor-bundle/amphp/parallel/docs/_config.yml b/vendor-bundle/amphp/parallel/docs/_config.yml new file mode 100644 index 000000000..cbdd980ae --- /dev/null +++ b/vendor-bundle/amphp/parallel/docs/_config.yml @@ -0,0 +1,29 @@ +kramdown: + input: GFM + toc_levels: 2..3 + +baseurl: "/parallel" +layouts_dir: ".shared/layout" +includes_dir: ".shared/includes" + +exclude: ["Gemfile", "Gemfile.lock", "README.md", "vendor"] +safe: true + +repository: amphp/parallel +gems: + - "jekyll-github-metadata" + - "jekyll-relative-links" + +defaults: + - scope: + path: "" + type: "pages" + values: + layout: "docs" + +shared_asset_path: "/parallel/asset" + +navigation: + - processes + - workers + - worker-pool diff --git a/vendor-bundle/amphp/parallel/lib/Context/Context.php b/vendor-bundle/amphp/parallel/lib/Context/Context.php new file mode 100644 index 000000000..4138c0aab --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Context/Context.php @@ -0,0 +1,30 @@ + Resolved once the context has started. + */ + public function start(); + /** + * Immediately kills the context. + */ + public function kill(); + /** + * @return \Amp\Promise Resolves with the returned from the context. + * + * @throws \Amp\Parallel\Context\ContextException If the context dies unexpectedly. + * @throws \Amp\Parallel\Sync\PanicError If the context throws an uncaught exception. + */ + public function join(); +} diff --git a/vendor-bundle/amphp/parallel/lib/Context/ContextException.php b/vendor-bundle/amphp/parallel/lib/Context/ContextException.php new file mode 100644 index 000000000..3638276e3 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Context/ContextException.php @@ -0,0 +1,7 @@ + + */ + public function run($script); +} diff --git a/vendor-bundle/amphp/parallel/lib/Context/DefaultContextFactory.php b/vendor-bundle/amphp/parallel/lib/Context/DefaultContextFactory.php new file mode 100644 index 000000000..59a727c64 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Context/DefaultContextFactory.php @@ -0,0 +1,48 @@ +events = new Events(); + $this->events->setBlocking(\false); + $channels =& $this->channels; + $this->watcher = Loop::repeat(self::EXIT_CHECK_FREQUENCY, static function () use(&$channels, $events) { + while ($event = $events->poll()) { + $id = (int) $event->source; + \assert(isset($channels[$id]), 'Channel for context ID not found'); + $channel = $channels[$id]; + unset($channels[$id]); + $channel->close(); + } + }); + Loop::disable($this->watcher); + Loop::unreference($this->watcher); + } + public function add($id, ChannelledSocket $channel, Future $future) + { + if (!\is_int($id)) { + if (!(\is_bool($id) || \is_numeric($id))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (int) $id; + } + } + $this->channels[$id] = $channel; + $this->events->addFuture((string) $id, $future); + Loop::enable($this->watcher); + } + public function remove($id) + { + if (!\is_int($id)) { + if (!(\is_bool($id) || \is_numeric($id))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (int) $id; + } + } + if (!isset($this->channels[$id])) { + return; + } + unset($this->channels[$id]); + $this->events->remove((string) $id); + if (empty($this->channels)) { + Loop::disable($this->watcher); + } + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Context/Internal/ProcessHub.php b/vendor-bundle/amphp/parallel/lib/Context/Internal/ProcessHub.php new file mode 100644 index 000000000..7143b0be6 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Context/Internal/ProcessHub.php @@ -0,0 +1,169 @@ +uri = "tcp://127.0.0.1:0"; + } else { + $suffix = \bin2hex(\random_bytes(10)); + $path = \sys_get_temp_dir() . "/amp-parallel-ipc-" . $suffix . ".sock"; + $this->uri = "unix://" . $path; + $this->toUnlink = $path; + } + $context = \stream_context_create(['socket' => ['backlog' => 128]]); + $this->server = \stream_socket_server($this->uri, $errno, $errstr, \STREAM_SERVER_BIND | \STREAM_SERVER_LISTEN, $context); + if (!$this->server) { + throw new \RuntimeException(\sprintf("Could not create IPC server: (Errno: %d) %s", $errno, $errstr)); + } + if ($isWindows) { + $name = \stream_socket_get_name($this->server, \false); + $port = \substr($name, \strrpos($name, ":") + 1); + $this->uri = "tcp://127.0.0.1:" . $port; + } + $keys =& $this->keys; + $acceptor =& $this->acceptor; + $this->watcher = Loop::onReadable($this->server, static function ($watcher, $server) use(&$keys, &$acceptor) { + if (!\is_string($watcher)) { + if (!(\is_string($watcher) || \is_object($watcher) && \method_exists($watcher, '__toString') || (\is_bool($watcher) || \is_numeric($watcher)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcher) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcher) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcher = (string) $watcher; + } + } + // Error reporting suppressed since stream_socket_accept() emits E_WARNING on client accept failure. + while ($client = @\stream_socket_accept($server, 0)) { + // Timeout of 0 to be non-blocking. + asyncCall(static function () use($client, &$keys, &$acceptor) { + $channel = new ChannelledSocket($client, $client); + try { + $received = (yield Promise\timeout($channel->receive(), self::KEY_RECEIVE_TIMEOUT)); + } catch (\Exception $exception) { + $channel->close(); + return; + // Ignore possible foreign connection attempt. + } catch (\Error $exception) { + $channel->close(); + return; + // Ignore possible foreign connection attempt. + } + if (!\is_string($received) || !isset($keys[$received])) { + $channel->close(); + return; + // Ignore possible foreign connection attempt. + } + $pid = $keys[$received]; + $deferred = $acceptor[$pid]; + unset($acceptor[$pid], $keys[$received]); + $deferred->resolve($channel); + }); + } + }); + Loop::disable($this->watcher); + } + public function __destruct() + { + Loop::cancel($this->watcher); + \fclose($this->server); + if ($this->toUnlink !== null) { + @\unlink($this->toUnlink); + } + } + public function getUri() + { + $phabelReturn = $this->uri; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function generateKey($pid, $length) + { + if (!\is_int($pid)) { + if (!(\is_bool($pid) || \is_numeric($pid))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($pid) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pid) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pid = (int) $pid; + } + } + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + $key = \random_bytes($length); + $this->keys[$key] = $pid; + $phabelReturn = $key; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function accept($pid) + { + if (!\is_int($pid)) { + if (!(\is_bool($pid) || \is_numeric($pid))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($pid) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pid) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pid = (int) $pid; + } + } + $phabelReturn = call(function () use($pid) { + $this->acceptor[$pid] = new Deferred(); + Loop::enable($this->watcher); + try { + $channel = (yield Promise\timeout($this->acceptor[$pid]->promise(), self::PROCESS_START_TIMEOUT)); + } catch (TimeoutException $exception) { + $key = \array_search($pid, $this->keys, \true); + \assert(\is_string($key), "Key for {$pid} not found"); + unset($this->acceptor[$pid], $this->keys[$key]); + throw new ContextException("Starting the process timed out", 0, $exception); + } finally { + if (empty($this->acceptor)) { + Loop::disable($this->watcher); + } + } + return $channel; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Context/Internal/Thread.php b/vendor-bundle/amphp/parallel/lib/Context/Internal/Thread.php new file mode 100644 index 000000000..d36e627eb --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Context/Internal/Thread.php @@ -0,0 +1,147 @@ +id = $id; + $this->function = $function; + $this->args = $args; + $this->socket = $socket; + } + /** + * Runs the thread code and the initialized function. + * + * @codeCoverageIgnore Only executed in thread. + */ + public function run() + { + \define("AMP_CONTEXT", "thread"); + \define("AMP_CONTEXT_ID", $this->id); + $phabel_5d556a592ce8c6c7 = \Phabel\Plugin\NestedExpressionFixer::returnMe(static function () { + $paths = [\dirname(__DIR__, 3) . \DIRECTORY_SEPARATOR . "vendor" . \DIRECTORY_SEPARATOR . "autoload.php", \dirname(__DIR__, 5) . \DIRECTORY_SEPARATOR . "autoload.php"]; + foreach ($paths as $path) { + if (\file_exists($path)) { + $autoloadPath = $path; + break; + } + } + if (!isset($autoloadPath)) { + throw new \Error("Could not locate autoload.php"); + } + require $autoloadPath; + })->bindTo(null, null); + /* First thing we need to do is re-initialize the class autoloader. If + * we don't do this first, any object of a class that was loaded after + * the thread started will just be garbage data and unserializable + * values (like resources) will be lost. This happens even with + * thread-safe objects. + */ + // Protect scope by using an unbound closure (protects static access as well). + $phabel_5d556a592ce8c6c7(); + // At this point, the thread environment has been prepared so begin using the thread. + if ($this->killed) { + return; + // Thread killed while requiring autoloader, simply exit. + } + Loop::run(function () { + $watcher = Loop::repeat(self::KILL_CHECK_FREQUENCY, function () { + if ($this->killed) { + Loop::stop(); + } + }); + Loop::unreference($watcher); + try { + $channel = new ChannelledSocket($this->socket, $this->socket); + yield from $this->execute($channel); + } catch (\Exception $exception) { + return; + // Parent context exited or destroyed thread, no need to continue. + } catch (\Error $exception) { + return; + // Parent context exited or destroyed thread, no need to continue. + } finally { + Loop::cancel($watcher); + } + }); + } + /** + * Sets a local variable to true so the running event loop can check for a kill signal. + */ + public function kill() + { + return $this->killed = \true; + } + /** + * @param \Amp\Parallel\Sync\Channel $channel + * + * @return \Generator + * + * @codeCoverageIgnore Only executed in thread. + */ + private function execute(Channel $channel) + { + try { + $result = new ExitSuccess((yield call($this->function, $channel, ...$this->args))); + } catch (\Exception $exception) { + $result = new ExitFailure($exception); + } catch (\Error $exception) { + $result = new ExitFailure($exception); + } + if ($this->killed) { + return; + // Parent is not listening for a result. + } + // Attempt to return the result. + try { + try { + (yield $channel->send($result)); + } catch (SerializationException $exception) { + // Serializing the result failed. Send the reason why. + (yield $channel->send(new ExitFailure($exception))); + } + } catch (ChannelException $exception) { + // The result was not sendable! The parent context must have died or killed the context. + } + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Context/Internal/process-runner.php b/vendor-bundle/amphp/parallel/lib/Context/Internal/process-runner.php new file mode 100644 index 000000000..021a42ef2 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Context/Internal/process-runner.php @@ -0,0 +1,116 @@ +send($key)); + } catch (\Exception $exception) { + \trigger_error("Could not send key to parent", \E_USER_ERROR); + exit(1); + } catch (\Error $exception) { + \trigger_error("Could not send key to parent", \E_USER_ERROR); + exit(1); + } + try { + if (!isset($argv[0])) { + throw new \Error("No script path given"); + } + if (!\is_file($argv[0])) { + throw new \Error(\sprintf("No script found at '%s' (be sure to provide the full path to the script)", $argv[0])); + } + try { + $phabel_98cd3053bed8de2a = function () use($argc, $argv) { + $phabelReturn = (require $argv[0]); + if (!\is_callable($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // Using $argc so it is available to the required script. + return $phabelReturn; + }; + // Protect current scope by requiring script within another function. + $callable = $phabel_98cd3053bed8de2a(); + } catch (\TypeError $exception) { + throw new \Error(\sprintf("Script '%s' did not return a callable function", $argv[0]), 0, $exception); + } catch (\ParseError $exception) { + throw new \Error(\sprintf("Script '%s' contains a parse error: " . $exception->getMessage(), $argv[0]), 0, $exception); + } + $result = new Sync\ExitSuccess(Promise\wait(call($callable, $channel))); + } catch (\Exception $exception) { + $result = new Sync\ExitFailure($exception); + } catch (\Error $exception) { + $result = new Sync\ExitFailure($exception); + } + try { + Promise\wait(call(function () use($channel, $result) { + try { + (yield $channel->send($result)); + } catch (Sync\SerializationException $exception) { + // Serializing the result failed. Send the reason why. + (yield $channel->send(new Sync\ExitFailure($exception))); + } + })); + } catch (\Exception $exception) { + \trigger_error("Could not send result to parent; be sure to shutdown the child before ending the parent", \E_USER_ERROR); + exit(1); + } catch (\Error $exception) { + \trigger_error("Could not send result to parent; be sure to shutdown the child before ending the parent", \E_USER_ERROR); + exit(1); + } +}; +$phabel_94a45e49c4fa39bc(); diff --git a/vendor-bundle/amphp/parallel/lib/Context/Parallel.php b/vendor-bundle/amphp/parallel/lib/Context/Parallel.php new file mode 100644 index 000000000..5f6c39b0a --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Context/Parallel.php @@ -0,0 +1,489 @@ + The thread object that was spawned. + */ + public static function run($script) + { + $thread = new self($script); + $phabelReturn = call(function () use($thread) { + (yield $thread->start()); + return $thread; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string|array $script Path to PHP script or array with first element as path and following elements options + * to the PHP script (e.g.: ['bin/worker', 'Option1Value', 'Option2Value']. + * + * @throws \Error Thrown if the pthreads extension is not available. + */ + public function __construct($script) + { + if (!self::isSupported()) { + throw new \Error("The parallel extension is required to create parallel threads."); + } + $this->hub = Loop::getState(self::class); + if (!$this->hub instanceof Internal\ParallelHub) { + $this->hub = new Internal\ParallelHub(); + Loop::setState(self::class, $this->hub); + } + if (\is_array($script)) { + $this->script = (string) \array_shift($script); + $this->args = \array_values(\array_map("strval", $script)); + } else { + $this->script = (string) $script; + } + if (self::$autoloadPath === null) { + $paths = [\dirname(__DIR__, 2) . \DIRECTORY_SEPARATOR . "vendor" . \DIRECTORY_SEPARATOR . "autoload.php", \dirname(__DIR__, 4) . \DIRECTORY_SEPARATOR . "autoload.php"]; + foreach ($paths as $path) { + if (\file_exists($path)) { + self::$autoloadPath = $path; + break; + } + } + if (self::$autoloadPath === null) { + throw new \Error("Could not locate autoload.php"); + } + } + } + /** + * Returns the thread to the condition before starting. The new thread can be started and run independently of the + * first thread. + */ + public function __clone() + { + $this->runtime = null; + $this->channel = null; + $this->id = null; + $this->oid = 0; + $this->killed = \false; + } + /** + * Kills the thread if it is still running. + * + * @throws \Amp\Parallel\Context\ContextException + */ + public function __destruct() + { + if (\getmypid() === $this->oid) { + $this->kill(); + } + } + /** + * Checks if the context is running. + * + * @return bool True if the context is running, otherwise false. + */ + public function isRunning() + { + $phabelReturn = $this->channel !== null; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Spawns the thread and begins the thread's execution. + * + * @return Promise Resolved once the thread has started. + * + * @throws \Amp\Parallel\Context\StatusError If the thread has already been started. + * @throws \Amp\Parallel\Context\ContextException If starting the thread was unsuccessful. + */ + public function start() + { + if ($this->oid !== 0) { + throw new StatusError('The thread has already been started.'); + } + $this->oid = \getmypid(); + $this->runtime = new Runtime(self::$autoloadPath); + $this->id = self::$nextId++; + $future = $this->runtime->run(static function ($id, $uri, $key, $path, array $argv) { + if (!\is_int($id)) { + if (!(\is_bool($id) || \is_numeric($id))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (int) $id; + } + } + if (!\is_string($uri)) { + if (!(\is_string($uri) || \is_object($uri) && \method_exists($uri, '__toString') || (\is_bool($uri) || \is_numeric($uri)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($uri) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($uri) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $uri = (string) $uri; + } + } + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + if (!\is_string($path)) { + if (!(\is_string($path) || \is_object($path) && \method_exists($path, '__toString') || (\is_bool($path) || \is_numeric($path)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($path) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($path) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $path = (string) $path; + } + } + // @codeCoverageIgnoreStart + // Only executed in thread. + \define("AMP_CONTEXT", "parallel"); + \define("AMP_CONTEXT_ID", $id); + if (!($socket = \stream_socket_client($uri, $errno, $errstr, 5, \STREAM_CLIENT_CONNECT))) { + \trigger_error("Could not connect to IPC socket", \E_USER_ERROR); + $phabelReturn = 1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + $channel = new ChannelledSocket($socket, $socket); + try { + Promise\wait($channel->send($key)); + } catch (\Exception $exception) { + \trigger_error("Could not send key to parent", \E_USER_ERROR); + $phabelReturn = 1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } catch (\Error $exception) { + \trigger_error("Could not send key to parent", \E_USER_ERROR); + $phabelReturn = 1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + try { + Loop::unreference(Loop::repeat(self::EXIT_CHECK_FREQUENCY, function () { + // Timer to give the chance for the PHP VM to be interrupted by Runtime::kill(), since system calls such as + // select() will not be interrupted. + })); + try { + if (!\is_file($path)) { + throw new \Error(\sprintf("No script found at '%s' (be sure to provide the full path to the script)", $path)); + } + $argc = \array_unshift($argv, $path); + try { + $phabel_b287bb527139f221 = \Phabel\Plugin\NestedExpressionFixer::returnMe(function () use($argc, $argv) { + $phabelReturn = (require $argv[0]); + if (!\is_callable($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // Using $argc so it is available to the required script. + return $phabelReturn; + })->bindTo(null, null); + // Protect current scope by requiring script within another function. + $callable = $phabel_b287bb527139f221(); + } catch (\TypeError $exception) { + throw new \Error(\sprintf("Script '%s' did not return a callable function", $path), 0, $exception); + } catch (\ParseError $exception) { + throw new \Error(\sprintf("Script '%s' contains a parse error", $path), 0, $exception); + } + $result = new ExitSuccess(Promise\wait(call($callable, $channel))); + } catch (\Exception $exception) { + $result = new ExitFailure($exception); + } catch (\Error $exception) { + $result = new ExitFailure($exception); + } + Promise\wait(call(function () use($channel, $result) { + try { + (yield $channel->send($result)); + } catch (SerializationException $exception) { + // Serializing the result failed. Send the reason why. + (yield $channel->send(new ExitFailure($exception))); + } + })); + } catch (\Exception $exception) { + \trigger_error("Could not send result to parent; be sure to shutdown the child before ending the parent", \E_USER_ERROR); + $phabelReturn = 1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } catch (\Error $exception) { + \trigger_error("Could not send result to parent; be sure to shutdown the child before ending the parent", \E_USER_ERROR); + $phabelReturn = 1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } finally { + $channel->close(); + } + $phabelReturn = 0; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + // @codeCoverageIgnoreEnd + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + }, [$this->id, $this->hub->getUri(), $this->hub->generateKey($this->id, self::KEY_LENGTH), $this->script, $this->args]); + $phabelReturn = call(function () use($future) { + try { + $this->channel = (yield $this->hub->accept($this->id)); + $this->hub->add($this->id, $this->channel, $future); + } catch (\Exception $exception) { + $this->kill(); + throw new ContextException("Starting the parallel runtime failed", 0, $exception); + } catch (\Error $exception) { + $this->kill(); + throw new ContextException("Starting the parallel runtime failed", 0, $exception); + } + if ($this->killed) { + $this->kill(); + } + return $this->id; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Immediately kills the context. + */ + public function kill() + { + $this->killed = \true; + if ($this->runtime !== null) { + try { + $this->runtime->kill(); + } finally { + $this->close(); + } + } + } + /** + * Closes channel and socket if still open. + */ + private function close() + { + $this->runtime = null; + if ($this->channel !== null) { + $this->channel->close(); + } + $this->channel = null; + $this->hub->remove($this->id); + } + /** + * Gets a promise that resolves when the context ends and joins with the + * parent context. + * + * @return \Amp\Promise + * + * @throws StatusError Thrown if the context has not been started. + * @throws SynchronizationError Thrown if an exit status object is not received. + * @throws ContextException If the context stops responding. + */ + public function join() + { + if ($this->channel === null) { + throw new StatusError('The thread has not been started or has already finished.'); + } + $phabelReturn = call(function () { + try { + $response = (yield $this->channel->receive()); + $this->close(); + } catch (\Exception $exception) { + $this->kill(); + throw new ContextException("Failed to receive result from thread", 0, $exception); + } catch (\Error $exception) { + $this->kill(); + throw new ContextException("Failed to receive result from thread", 0, $exception); + } + if (!$response instanceof ExitResult) { + $this->kill(); + throw new SynchronizationError('Did not receive an exit result from thread.'); + } + return $response->getResult(); + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function receive() + { + if ($this->channel === null) { + throw new StatusError('The thread has not been started.'); + } + $phabelReturn = call(function () { + try { + $data = (yield $this->channel->receive()); + } catch (ChannelException $e) { + throw new ContextException("The thread stopped responding, potentially due to a fatal error or calling exit", 0, $e); + } + if ($data instanceof ExitResult) { + $data = $data->getResult(); + throw new SynchronizationError(\sprintf('Thread unexpectedly exited with result of type: %s', \is_object($data) ? \get_class($data) : \gettype($data))); + } + return $data; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function send($data) + { + if ($this->channel === null) { + throw new StatusError('The thread has not been started or has already finished.'); + } + if ($data instanceof ExitResult) { + throw new \Error('Cannot send exit result objects.'); + } + $phabelReturn = call(function () use($data) { + try { + return (yield $this->channel->send($data)); + } catch (ChannelException $e) { + if ($this->channel === null) { + throw new ContextException("The thread stopped responding, potentially due to a fatal error or calling exit", 0, $e); + } + try { + $data = (yield Promise\timeout($this->join(), 100)); + } catch (ContextException $ex) { + $this->kill(); + throw new ContextException("The thread stopped responding, potentially due to a fatal error or calling exit", 0, $e); + } catch (ChannelException $ex) { + $this->kill(); + throw new ContextException("The thread stopped responding, potentially due to a fatal error or calling exit", 0, $e); + } catch (TimeoutException $ex) { + $this->kill(); + throw new ContextException("The thread stopped responding, potentially due to a fatal error or calling exit", 0, $e); + } + throw new SynchronizationError(\sprintf('Thread unexpectedly exited with result of type: %s', \is_object($data) ? \get_class($data) : \gettype($data)), 0, $e); + } + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Returns the ID of the thread. This ID will be unique to this process. + * + * @return int + * + * @throws \Amp\Process\StatusError + */ + public function getId() + { + if ($this->id === null) { + throw new StatusError('The thread has not been started'); + } + $phabelReturn = $this->id; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Context/Process.php b/vendor-bundle/amphp/parallel/lib/Context/Process.php new file mode 100644 index 000000000..241b593e6 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Context/Process.php @@ -0,0 +1,456 @@ + + */ + public static function run($script, $cwd = null, array $env = [], $binary = null) + { + if (!\is_null($cwd)) { + if (!\is_string($cwd)) { + if (!(\is_string($cwd) || \is_object($cwd) && \method_exists($cwd, '__toString') || (\is_bool($cwd) || \is_numeric($cwd)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($cwd) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cwd) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cwd = (string) $cwd; + } + } + } + if (!\is_null($binary)) { + if (!\is_string($binary)) { + if (!(\is_string($binary) || \is_object($binary) && \method_exists($binary, '__toString') || (\is_bool($binary) || \is_numeric($binary)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($binary) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($binary) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $binary = (string) $binary; + } + } + } + $process = new self($script, $cwd, $env, $binary); + $phabelReturn = call(function () use($process) { + (yield $process->start()); + return $process; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string|array $script Path to PHP script or array with first element as path and following elements options + * to the PHP script (e.g.: ['bin/worker', 'Option1Value', 'Option2Value']. + * @param string|null $cwd Working directory. + * @param mixed[] $env Array of environment variables. + * @param string $binary Path to PHP binary. Null will attempt to automatically locate the binary. + * + * @throws \Error If the PHP binary path given cannot be found or is not executable. + */ + public function __construct($script, $cwd = null, array $env = [], $binary = null) + { + if (!\is_null($cwd)) { + if (!\is_string($cwd)) { + if (!(\is_string($cwd) || \is_object($cwd) && \method_exists($cwd, '__toString') || (\is_bool($cwd) || \is_numeric($cwd)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($cwd) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cwd) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cwd = (string) $cwd; + } + } + } + if (!\is_null($binary)) { + if (!\is_string($binary)) { + if (!(\is_string($binary) || \is_object($binary) && \method_exists($binary, '__toString') || (\is_bool($binary) || \is_numeric($binary)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($binary) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($binary) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $binary = (string) $binary; + } + } + } + $this->hub = Loop::getState(self::class); + if (!$this->hub instanceof Internal\ProcessHub) { + $this->hub = new Internal\ProcessHub(); + Loop::setState(self::class, $this->hub); + } + $options = ["html_errors" => "0", "display_errors" => "0", "log_errors" => "1"]; + if ($binary === null) { + if (\PHP_SAPI === "cli") { + $binary = \PHP_BINARY; + } else { + $binary = isset(self::$binaryPath) ? self::$binaryPath : self::locateBinary(); + } + } elseif (!\is_executable($binary)) { + throw new \Error(\sprintf("The PHP binary path '%s' was not found or is not executable", $binary)); + } + // Write process runner to external file if inside a PHAR, + // because PHP can't open files inside a PHAR directly except for the stub. + if (\strpos(self::SCRIPT_PATH, "phar://") === 0) { + if (self::$pharScriptPath) { + $scriptPath = self::$pharScriptPath; + } else { + $path = \dirname(self::SCRIPT_PATH); + if (\substr(\Phar::running(\false), -5) !== ".phar") { + self::$pharCopy = \sys_get_temp_dir() . "/phar-" . \bin2hex(\random_bytes(10)) . ".phar"; + \copy(\Phar::running(\false), self::$pharCopy); + \register_shutdown_function(static function () { + @\unlink(self::$pharCopy); + }); + $path = "phar://" . self::$pharCopy . "/" . \substr($path, \strlen(\Phar::running(\true))); + } + $contents = \file_get_contents(self::SCRIPT_PATH); + $contents = \str_replace("__DIR__", \var_export($path, \true), $contents); + $suffix = \bin2hex(\random_bytes(10)); + self::$pharScriptPath = $scriptPath = \sys_get_temp_dir() . "/amp-process-runner-" . $suffix . ".php"; + \file_put_contents($scriptPath, $contents); + \register_shutdown_function(static function () { + @\unlink(self::$pharScriptPath); + }); + } + // Monkey-patch the script path in the same way, only supported if the command is given as array. + if (isset(self::$pharCopy) && \is_array($script) && isset($script[0])) { + $script[0] = "phar://" . self::$pharCopy . \substr($script[0], \strlen(\Phar::running(\true))); + } + } else { + $scriptPath = self::SCRIPT_PATH; + } + if (\is_array($script)) { + $script = \implode(" ", \array_map("escapeshellarg", $script)); + } else { + $script = \escapeshellarg($script); + } + $command = \implode(" ", [\escapeshellarg($binary), $this->formatOptions($options), \escapeshellarg($scriptPath), $this->hub->getUri(), $script]); + $this->process = new BaseProcess($command, $cwd, $env); + } + private static function locateBinary() + { + $executable = \strncasecmp(\PHP_OS, "WIN", 3) === 0 ? "php.exe" : "php"; + $paths = \array_filter(\explode(\PATH_SEPARATOR, \getenv("PATH"))); + $paths[] = \PHP_BINDIR; + $paths = \array_unique($paths); + foreach ($paths as $path) { + $path .= \DIRECTORY_SEPARATOR . $executable; + if (\is_executable($path)) { + $phabelReturn = self::$binaryPath = $path; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + } + throw new \Error("Could not locate PHP executable binary"); + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + private function formatOptions(array $options) + { + $result = []; + foreach ($options as $option => $value) { + $result[] = \sprintf("-d%s=%s", $option, $value); + } + $phabelReturn = \implode(" ", $result); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Private method to prevent cloning. + */ + private function __clone() + { + } + /** + * {@inheritdoc} + */ + public function start() + { + $phabelReturn = call(function () { + try { + $pid = (yield $this->process->start()); + (yield $this->process->getStdin()->write($this->hub->generateKey($pid, self::KEY_LENGTH))); + $this->channel = (yield $this->hub->accept($pid)); + return $pid; + } catch (\Exception $exception) { + if ($this->isRunning()) { + $this->kill(); + } + throw new ContextException("Starting the process failed", 0, $exception); + } catch (\Error $exception) { + if ($this->isRunning()) { + $this->kill(); + } + throw new ContextException("Starting the process failed", 0, $exception); + } + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function isRunning() + { + $phabelReturn = $this->process->isRunning(); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function receive() + { + if ($this->channel === null) { + throw new StatusError("The process has not been started"); + } + $phabelReturn = call(function () { + try { + $data = (yield $this->channel->receive()); + } catch (ChannelException $e) { + throw new ContextException("The process stopped responding, potentially due to a fatal error or calling exit", 0, $e); + } + if ($data instanceof ExitResult) { + $data = $data->getResult(); + throw new SynchronizationError(\sprintf('Process unexpectedly exited with result of type: %s', \is_object($data) ? \get_class($data) : \gettype($data))); + } + return $data; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function send($data) + { + if ($this->channel === null) { + throw new StatusError("The process has not been started"); + } + if ($data instanceof ExitResult) { + throw new \Error("Cannot send exit result objects"); + } + $phabelReturn = call(function () use($data) { + try { + return (yield $this->channel->send($data)); + } catch (ChannelException $e) { + if ($this->channel === null) { + throw new ContextException("The process stopped responding, potentially due to a fatal error or calling exit", 0, $e); + } + try { + $data = (yield Promise\timeout($this->join(), 100)); + } catch (ContextException $ex) { + if ($this->isRunning()) { + $this->kill(); + } + throw new ContextException("The process stopped responding, potentially due to a fatal error or calling exit", 0, $e); + } catch (ChannelException $ex) { + if ($this->isRunning()) { + $this->kill(); + } + throw new ContextException("The process stopped responding, potentially due to a fatal error or calling exit", 0, $e); + } catch (TimeoutException $ex) { + if ($this->isRunning()) { + $this->kill(); + } + throw new ContextException("The process stopped responding, potentially due to a fatal error or calling exit", 0, $e); + } + throw new SynchronizationError(\sprintf('Process unexpectedly exited with result of type: %s', \is_object($data) ? \get_class($data) : \gettype($data)), 0, $e); + } + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function join() + { + if ($this->channel === null) { + throw new StatusError("The process has not been started"); + } + $phabelReturn = call(function () { + try { + $data = (yield $this->channel->receive()); + } catch (\Exception $exception) { + if ($this->isRunning()) { + $this->kill(); + } + throw new ContextException("Failed to receive result from process", 0, $exception); + } catch (\Error $exception) { + if ($this->isRunning()) { + $this->kill(); + } + throw new ContextException("Failed to receive result from process", 0, $exception); + } + if (!$data instanceof ExitResult) { + if ($this->isRunning()) { + $this->kill(); + } + throw new SynchronizationError("Did not receive an exit result from process"); + } + $this->channel->close(); + $code = (yield $this->process->join()); + if ($code !== 0) { + throw new ContextException(\sprintf("Process exited with code %d", $code)); + } + return $data->getResult(); + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Send a signal to the process. + * + * @see \Amp\Process\Process::signal() + * + * @param int $signo + * + * @throws \Amp\Process\ProcessException + * @throws \Amp\Process\StatusError + */ + public function signal($signo) + { + if (!\is_int($signo)) { + if (!(\is_bool($signo) || \is_numeric($signo))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($signo) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signo) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signo = (int) $signo; + } + } + $this->process->signal($signo); + } + /** + * Returns the PID of the process. + * + * @see \Amp\Process\Process::getPid() + * + * @return int + * + * @throws \Amp\Process\StatusError + */ + public function getPid() + { + $phabelReturn = $this->process->getPid(); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Returns the STDIN stream of the process. + * + * @see \Amp\Process\Process::getStdin() + * + * @return ProcessOutputStream + * + * @throws \Amp\Process\StatusError + */ + public function getStdin() + { + $phabelReturn = $this->process->getStdin(); + if (!$phabelReturn instanceof ProcessOutputStream) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ProcessOutputStream, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Returns the STDOUT stream of the process. + * + * @see \Amp\Process\Process::getStdout() + * + * @return ProcessInputStream + * + * @throws \Amp\Process\StatusError + */ + public function getStdout() + { + $phabelReturn = $this->process->getStdout(); + if (!$phabelReturn instanceof ProcessInputStream) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ProcessInputStream, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Returns the STDOUT stream of the process. + * + * @see \Amp\Process\Process::getStderr() + * + * @return ProcessInputStream + * + * @throws \Amp\Process\StatusError + */ + public function getStderr() + { + $phabelReturn = $this->process->getStderr(); + if (!$phabelReturn instanceof ProcessInputStream) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ProcessInputStream, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function kill() + { + $this->process->kill(); + if ($this->channel !== null) { + $this->channel->close(); + } + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Context/StatusError.php b/vendor-bundle/amphp/parallel/lib/Context/StatusError.php new file mode 100644 index 000000000..28fde78c0 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Context/StatusError.php @@ -0,0 +1,7 @@ + The thread object that was spawned. + */ + public static function run(callable $function, ...$args) + { + $thread = new self($function, ...$args); + $phabelReturn = call(function () use($thread) { + (yield $thread->start()); + return $thread; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Creates a new thread. + * + * @param callable $function The callable to invoke in the thread. First argument is an instance of + * \Amp\Parallel\Sync\Channel. + * @param mixed ...$args Additional arguments to pass to the given callable. + * + * @throws \Error Thrown if the pthreads extension is not available. + */ + public function __construct(callable $function, ...$args) + { + if (!self::isSupported()) { + throw new \Error("The pthreads extension is required to create threads."); + } + $this->function = $function; + $this->args = $args; + } + /** + * Returns the thread to the condition before starting. The new thread can be started and run independently of the + * first thread. + */ + public function __clone() + { + $this->thread = null; + $this->socket = null; + $this->channel = null; + $this->oid = 0; + } + /** + * Kills the thread if it is still running. + * + * @throws \Amp\Parallel\Context\ContextException + */ + public function __destruct() + { + if (\getmypid() === $this->oid) { + $this->kill(); + } + } + /** + * Checks if the context is running. + * + * @return bool True if the context is running, otherwise false. + */ + public function isRunning() + { + $phabelReturn = $this->channel !== null; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Spawns the thread and begins the thread's execution. + * + * @return Promise Resolved once the thread has started. + * + * @throws \Amp\Parallel\Context\StatusError If the thread has already been started. + * @throws \Amp\Parallel\Context\ContextException If starting the thread was unsuccessful. + */ + public function start() + { + if ($this->oid !== 0) { + throw new StatusError('The thread has already been started.'); + } + $this->oid = \getmypid(); + $sockets = @\stream_socket_pair(\stripos(\PHP_OS, "win") === 0 ? \STREAM_PF_INET : \STREAM_PF_UNIX, \STREAM_SOCK_STREAM, \STREAM_IPPROTO_IP); + if ($sockets === \false) { + $message = "Failed to create socket pair"; + if ($error = \error_get_last()) { + $message .= \sprintf(" Errno: %d; %s", $error["type"], $error["message"]); + } + $phabelReturn = new Failure(new ContextException($message)); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + list($channel, $this->socket) = $sockets; + $this->id = self::$nextId++; + $thread = $this->thread = new Internal\Thread($this->id, $this->socket, $this->function, $this->args); + if (!$this->thread->start(\PTHREADS_INHERIT_INI)) { + $phabelReturn = new Failure(new ContextException('Failed to start the thread.')); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $channel = $this->channel = new ChannelledSocket($channel, $channel); + $this->watcher = Loop::repeat(self::EXIT_CHECK_FREQUENCY, static function ($watcher) use($thread, $channel) { + if (!$thread->isRunning()) { + // Delay closing to avoid race condition between thread exiting and data becoming available. + Loop::delay(self::EXIT_CHECK_FREQUENCY, [$channel, "close"]); + Loop::cancel($watcher); + } + }); + Loop::disable($this->watcher); + $phabelReturn = new Success($this->id); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Immediately kills the context. + * + * @throws ContextException If killing the thread was unsuccessful. + */ + public function kill() + { + if ($this->thread !== null) { + try { + if ($this->thread->isRunning() && !$this->thread->kill()) { + throw new ContextException('Could not kill thread.'); + } + } finally { + $this->close(); + } + } + } + /** + * Closes channel and socket if still open. + */ + private function close() + { + if ($this->channel !== null) { + $this->channel->close(); + } + $this->channel = null; + Loop::cancel($this->watcher); + } + /** + * Gets a promise that resolves when the context ends and joins with the + * parent context. + * + * @return \Amp\Promise + * + * @throws StatusError Thrown if the context has not been started. + * @throws SynchronizationError Thrown if an exit status object is not received. + * @throws ContextException If the context stops responding. + */ + public function join() + { + if ($this->channel == null || $this->thread === null) { + throw new StatusError('The thread has not been started or has already finished.'); + } + $phabelReturn = call(function () { + Loop::enable($this->watcher); + try { + $response = (yield $this->channel->receive()); + } catch (\Exception $exception) { + $this->kill(); + throw new ContextException("Failed to receive result from thread", 0, $exception); + } catch (\Error $exception) { + $this->kill(); + throw new ContextException("Failed to receive result from thread", 0, $exception); + } finally { + Loop::disable($this->watcher); + $this->close(); + } + if (!$response instanceof ExitResult) { + $this->kill(); + throw new SynchronizationError('Did not receive an exit result from thread.'); + } + return $response->getResult(); + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function receive() + { + if ($this->channel === null) { + throw new StatusError('The process has not been started.'); + } + $phabelReturn = call(function () { + Loop::enable($this->watcher); + try { + $data = (yield $this->channel->receive()); + } finally { + Loop::disable($this->watcher); + } + if ($data instanceof ExitResult) { + $data = $data->getResult(); + throw new SynchronizationError(\sprintf('Thread process unexpectedly exited with result of type: %s', \is_object($data) ? \get_class($data) : \gettype($data))); + } + return $data; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function send($data) + { + if ($this->channel === null) { + throw new StatusError('The thread has not been started or has already finished.'); + } + if ($data instanceof ExitResult) { + throw new \Error('Cannot send exit result objects.'); + } + $phabelReturn = call(function () use($data) { + Loop::enable($this->watcher); + try { + $result = (yield $this->channel->send($data)); + } finally { + Loop::disable($this->watcher); + } + return $result; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Returns the ID of the thread. This ID will be unique to this process. + * + * @return int + * + * @throws \Amp\Process\StatusError + */ + public function getId() + { + if ($this->id === null) { + throw new StatusError('The thread has not been started'); + } + $phabelReturn = $this->id; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Context/functions.php b/vendor-bundle/amphp/parallel/lib/Context/functions.php new file mode 100644 index 000000000..489cbb64d --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Context/functions.php @@ -0,0 +1,68 @@ +create($script); + if (!$phabelReturn instanceof Context) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Context, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Creates and starts a process based on installed extensions (a thread if ext-parallel is installed, otherwise a child + * process). + * + * @param string|string[] $script Path to PHP script or array with first element as path and following elements options + * to the PHP script (e.g.: ['bin/worker', 'Option1Value', 'Option2Value']. + * + * @return Promise + */ +function run($script) +{ + $phabelReturn = factory()->run($script); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Gets or sets the global context factory. + * + * @param ContextFactory|null $factory + * + * @return ContextFactory + */ +function factory($factory = null) +{ + if (!($factory instanceof ContextFactory || \is_null($factory))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($factory) must be of type ?ContextFactory, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($factory) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if ($factory === null) { + $factory = Loop::getState(LOOP_FACTORY_IDENTIFIER); + if ($factory) { + $phabelReturn = $factory; + if (!$phabelReturn instanceof ContextFactory) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ContextFactory, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $factory = new DefaultContextFactory(); + } + Loop::setState(LOOP_FACTORY_IDENTIFIER, $factory); + $phabelReturn = $factory; + if (!$phabelReturn instanceof ContextFactory) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ContextFactory, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/Channel.php b/vendor-bundle/amphp/parallel/lib/Sync/Channel.php new file mode 100644 index 000000000..0229892ef --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/Channel.php @@ -0,0 +1,34 @@ + + * + * @throws \Amp\Parallel\Context\StatusError Thrown if the context has not been started. + * @throws \Amp\Parallel\Sync\SynchronizationError If the context has not been started or the context + * unexpectedly ends. + * @throws \Amp\Parallel\Sync\ChannelException If receiving from the channel fails. + * @throws \Amp\Parallel\Sync\SerializationException If unserializing the data fails. + */ + public function receive(); + /** + * @param mixed $data + * + * @return \Amp\Promise Resolves with the number of bytes sent on the channel. + * + * @throws \Amp\Parallel\Context\StatusError Thrown if the context has not been started. + * @throws \Amp\Parallel\Sync\SynchronizationError If the context has not been started or the context + * unexpectedly ends. + * @throws \Amp\Parallel\Sync\ChannelException If sending on the channel fails. + * @throws \Error If an ExitResult object is given. + * @throws \Amp\Parallel\Sync\SerializationException If serializing the data fails. + */ + public function send($data); +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/ChannelException.php b/vendor-bundle/amphp/parallel/lib/Sync/ChannelException.php new file mode 100644 index 000000000..481523c91 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/ChannelException.php @@ -0,0 +1,7 @@ +serializer = isset($serializer) ? $serializer : new NativeSerializer(); + parent::__construct(self::parser($callback, $this->serializer)); + } + /** + * @param mixed $data Data to encode to send over a channel. + * + * @return string Encoded data that can be parsed by this class. + * + * @throws SerializationException + */ + public function encode($data) + { + $data = $this->serializer->serialize($data); + $phabelReturn = \pack("CL", 0, \strlen($data)) . $data; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @param callable $push + * @param Serializer $serializer + * + * @return \Generator + * + * @throws ChannelException + * @throws SerializationException + */ + private static function parser(callable $push, Serializer $serializer) + { + while (\true) { + $header = (yield self::HEADER_LENGTH); + $data = \unpack("Cprefix/Llength", $header); + if ($data["prefix"] !== 0) { + $data = $header . yield; + throw new ChannelException("Invalid packet received: " . encodeUnprintableChars($data)); + } + $data = (yield $data["length"]); + $push($serializer->unserialize($data)); + } + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/ChannelledSocket.php b/vendor-bundle/amphp/parallel/lib/Sync/ChannelledSocket.php new file mode 100644 index 000000000..705cf4fbd --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/ChannelledSocket.php @@ -0,0 +1,69 @@ +channel = new ChannelledStream($this->read = new ResourceInputStream($read), $this->write = new ResourceOutputStream($write), $serializer); + } + /** + * {@inheritdoc} + */ + public function receive() + { + $phabelReturn = $this->channel->receive(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function send($data) + { + $phabelReturn = $this->channel->send($data); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function unreference() + { + $this->read->unreference(); + } + public function reference() + { + $this->read->reference(); + } + /** + * Closes the read and write resource streams. + */ + public function close() + { + $this->read->close(); + $this->write->close(); + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/ChannelledStream.php b/vendor-bundle/amphp/parallel/lib/Sync/ChannelledStream.php new file mode 100644 index 000000000..ef8dae3f3 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/ChannelledStream.php @@ -0,0 +1,84 @@ +read = $read; + $this->write = $write; + $this->received = new \SplQueue(); + $this->parser = new ChannelParser([$this->received, 'push'], $serializer); + } + /** + * {@inheritdoc} + */ + public function send($data) + { + $phabelReturn = call(function () use($data) { + try { + return (yield $this->write->write($this->parser->encode($data))); + } catch (StreamException $exception) { + throw new ChannelException("Sending on the channel failed. Did the context die?", 0, $exception); + } + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function receive() + { + $phabelReturn = call(function () { + while ($this->received->isEmpty()) { + try { + $chunk = (yield $this->read->read()); + } catch (StreamException $exception) { + throw new ChannelException("Reading from the channel failed. Did the context die?", 0, $exception); + } + if ($chunk === null) { + throw new ChannelException("The channel closed unexpectedly. Did the context die?"); + } + $this->parser->push($chunk); + } + return $this->received->shift(); + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/ContextPanicError.php b/vendor-bundle/amphp/parallel/lib/Sync/ContextPanicError.php new file mode 100644 index 000000000..91d5b988e --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/ContextPanicError.php @@ -0,0 +1,115 @@ +originalMessage = $message; + $this->originalCode = $code; + $this->originalTrace = $trace; + } + /** + * @return string Original exception class name. + */ + public function getOriginalClassName() + { + $phabelReturn = $this->getName(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return string Original exception message. + */ + public function getOriginalMessage() + { + $phabelReturn = $this->originalMessage; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return int|string Original exception code. + */ + public function getOriginalCode() + { + return $this->originalCode; + } + /** + * Original exception stack trace. + * + * @return array Same as {@see Throwable::getTrace()}, except all function arguments are formatted as strings. + */ + public function getOriginalTrace() + { + $phabelReturn = $this->originalTrace; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Original backtrace flattened to a human-readable string. + * + * @return string + */ + public function getOriginalTraceAsString() + { + $phabelReturn = $this->getPanicTrace(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/ExitFailure.php b/vendor-bundle/amphp/parallel/lib/Sync/ExitFailure.php new file mode 100644 index 000000000..c45147ac9 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/ExitFailure.php @@ -0,0 +1,43 @@ +type = \get_class($exception); + $this->message = $exception->getMessage(); + $this->code = $exception->getCode(); + $this->trace = flattenThrowableBacktrace($exception); + if ($previous = $exception->getPrevious()) { + $this->previous = new self($previous); + } + } + /** + * {@inheritdoc} + */ + public function getResult() + { + throw $this->createException(); + } + private function createException() + { + $previous = $this->previous ? $this->previous->createException() : null; + $phabelReturn = new ContextPanicError($this->type, $this->message, $this->code, $this->trace, $previous); + if (!$phabelReturn instanceof ContextPanicError) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ContextPanicError, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/ExitResult.php b/vendor-bundle/amphp/parallel/lib/Sync/ExitResult.php new file mode 100644 index 000000000..baa3afba0 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/ExitResult.php @@ -0,0 +1,13 @@ +result = $result; + } + /** + * {@inheritdoc} + */ + public function getResult() + { + return $this->result; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/Internal/ParcelStorage.php b/vendor-bundle/amphp/parallel/lib/Sync/Internal/ParcelStorage.php new file mode 100644 index 000000000..35d7ca5be --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/Internal/ParcelStorage.php @@ -0,0 +1,30 @@ +value = $value; + } + /** + * @return mixed + */ + public function get() + { + return $this->value; + } + /** + * @param mixed $value + */ + public function set($value) + { + $this->value = $value; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/PanicError.php b/vendor-bundle/amphp/parallel/lib/Sync/PanicError.php new file mode 100644 index 000000000..b9cd12320 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/PanicError.php @@ -0,0 +1,91 @@ +name = $name; + $this->trace = $trace; + } + /** + * @deprecated Use ContextPanicError::getOriginalClassName() instead. + * + * Returns the class name of the uncaught exception. + * + * @return string + */ + public function getName() + { + $phabelReturn = $this->name; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @deprecated Use ContextPanicError::getOriginalTraceAsString() instead. + * + * Gets the stack trace at the point the panic occurred. + * + * @return string + */ + public function getPanicTrace() + { + $phabelReturn = $this->trace; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/Parcel.php b/vendor-bundle/amphp/parallel/lib/Sync/Parcel.php new file mode 100644 index 000000000..bce4b19f6 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/Parcel.php @@ -0,0 +1,36 @@ + Resolves with the return value of $callback or fails if $callback + * throws an exception. + */ + public function synchronized(callable $callback); + /** + * @return \Amp\Promise A promise for the value inside the parcel. + */ + public function unwrap(); +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/ParcelException.php b/vendor-bundle/amphp/parallel/lib/Sync/ParcelException.php new file mode 100644 index 000000000..0d8c75e80 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/ParcelException.php @@ -0,0 +1,7 @@ +init($value, $size, $permissions); + $phabelReturn = $parcel; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string $id + * @param Serializer|null $serializer + * + * @return self + * + * @throws SharedMemoryException + */ + public static function use_($id, $serializer = null) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + if (!($serializer instanceof Serializer || \is_null($serializer))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($serializer) must be of type ?Serializer, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($serializer) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $parcel = new self($id, $serializer); + $parcel->open(); + $phabelReturn = $parcel; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string $id + * @param Serializer|null $serializer + */ + private function __construct($id, $serializer = null) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + if (!($serializer instanceof Serializer || \is_null($serializer))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($serializer) must be of type ?Serializer, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($serializer) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\extension_loaded("shmop")) { + throw new \Error(__CLASS__ . " requires the shmop extension"); + } + $this->id = $id; + $this->key = self::makeKey($this->id); + $this->serializer = isset($serializer) ? $serializer : new NativeSerializer(); + } + /** + * @param mixed $value + * @param int $size + * @param int $permissions + * + * @throws SharedMemoryException + * @throws SyncException + * @throws \Error If the size or permissions are invalid. + */ + private function init($value, $size = 8192, $permissions = 0600) + { + if (!\is_int($size)) { + if (!(\is_bool($size) || \is_numeric($size))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($size) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($size) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $size = (int) $size; + } + } + if (!\is_int($permissions)) { + if (!(\is_bool($permissions) || \is_numeric($permissions))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($permissions) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($permissions) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $permissions = (int) $permissions; + } + } + if ($size <= 0) { + throw new \Error('The memory size must be greater than 0'); + } + if ($permissions <= 0 || $permissions > 0777) { + throw new \Error('Invalid permissions'); + } + $this->semaphore = PosixSemaphore::create($this->id, 1); + $this->initializer = \getmypid(); + $this->memOpen($this->key, 'n', $permissions, $size + self::MEM_DATA_OFFSET); + $this->setHeader(self::STATE_ALLOCATED, 0, $permissions); + $this->wrap($value); + } + private function open() + { + $this->semaphore = PosixSemaphore::use_($this->id); + $this->memOpen($this->key, 'w', 0, 0); + } + /** + * Checks if the object has been freed. + * + * Note that this does not check if the object has been destroyed; it only + * checks if this handle has freed its reference to the object. + * + * @return bool True if the object is freed, otherwise false. + */ + private function isFreed() + { + // If we are no longer connected to the memory segment, check if it has + // been invalidated. + if ($this->handle !== null) { + $this->handleMovedMemory(); + $header = $this->getHeader(); + $phabelReturn = $header['state'] === static::STATE_FREED; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function unwrap() + { + $phabelReturn = call(function () { + $lock = (yield $this->semaphore->acquire()); + \assert($lock instanceof Lock); + try { + return $this->getValue(); + } finally { + $lock->release(); + } + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return mixed + * + * @throws SharedMemoryException + * @throws SerializationException + */ + private function getValue() + { + if ($this->isFreed()) { + throw new SharedMemoryException('The object has already been freed'); + } + $header = $this->getHeader(); + // Make sure the header is in a valid state and format. + if ($header['state'] !== self::STATE_ALLOCATED || $header['size'] <= 0) { + throw new SharedMemoryException('Shared object memory is corrupt'); + } + // Read the actual value data from memory and unserialize it. + $data = $this->memGet(self::MEM_DATA_OFFSET, $header['size']); + return $this->serializer->unserialize($data); + } + /** + * If the value requires more memory to store than currently allocated, a + * new shared memory segment will be allocated with a larger size to store + * the value in. The previous memory segment will be cleaned up and marked + * for deletion. Other processes and threads will be notified of the new + * memory segment on the next read attempt. Once all running processes and + * threads disconnect from the old segment, it will be freed by the OS. + */ + private function wrap($value) + { + if ($this->isFreed()) { + throw new SharedMemoryException('The object has already been freed'); + } + $serialized = $this->serializer->serialize($value); + $size = \strlen($serialized); + $header = $this->getHeader(); + /* If we run out of space, we need to allocate a new shared memory + segment that is larger than the current one. To coordinate with other + processes, we will leave a message in the old segment that the segment + has moved and along with the new key. The old segment will be discarded + automatically after all other processes notice the change and close + the old handle. + */ + if (\shmop_size($this->handle) < $size + self::MEM_DATA_OFFSET) { + $this->key = $this->key < 0xffffffff ? $this->key + 1 : \random_int(0x10, 0xfffffffe); + $this->setHeader(self::STATE_MOVED, $this->key, 0); + $this->memDelete(); + \shmop_close($this->handle); + $this->memOpen($this->key, 'n', $header['permissions'], $size * 2); + } + // Rewrite the header and the serialized value to memory. + $this->setHeader(self::STATE_ALLOCATED, $size, $header['permissions']); + $this->memSet(self::MEM_DATA_OFFSET, $serialized); + } + /** + * {@inheritdoc} + */ + public function synchronized(callable $callback) + { + $phabelReturn = call(function () use($callback) { + $lock = (yield $this->semaphore->acquire()); + \assert($lock instanceof Lock); + try { + $result = (yield call($callback, $this->getValue())); + if ($result !== null) { + $this->wrap($result); + } + } finally { + $lock->release(); + } + return $result; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Frees the shared object from memory. + * + * The memory containing the shared value will be invalidated. When all + * process disconnect from the object, the shared memory block will be + * destroyed by the OS. + */ + public function __destruct() + { + if ($this->initializer === 0 || $this->initializer !== \getmypid()) { + return; + } + if ($this->isFreed()) { + return; + } + // Invalidate the memory block by setting its state to FREED. + $this->setHeader(static::STATE_FREED, 0, 0); + // Request the block to be deleted, then close our local handle. + $this->memDelete(); + \shmop_close($this->handle); + $this->handle = null; + $this->semaphore = null; + } + /** + * Private method to prevent cloning. + */ + private function __clone() + { + } + /** + * Private method to prevent serialization. + */ + private function __sleep() + { + } + /** + * Updates the current memory segment handle, handling any moves made on the + * data. + * + * @throws SharedMemoryException + */ + private function handleMovedMemory() + { + // Read from the memory block and handle moved blocks until we find the + // correct block. + while (\true) { + $header = $this->getHeader(); + // If the state is STATE_MOVED, the memory is stale and has been moved + // to a new location. Move handle and try to read again. + if ($header['state'] !== self::STATE_MOVED) { + break; + } + \shmop_close($this->handle); + $this->key = $header['size']; + $this->memOpen($this->key, 'w', 0, 0); + } + } + /** + * Reads and returns the data header at the current memory segment. + * + * @return array An associative array of header data. + * + * @throws SharedMemoryException + */ + private function getHeader() + { + $data = $this->memGet(0, self::MEM_DATA_OFFSET); + $phabelReturn = \unpack('Cstate/Lsize/Spermissions', $data); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Sets the header data for the current memory segment. + * + * @param int $state An object state. + * @param int $size The size of the stored data, or other value. + * @param int $permissions The permissions mask on the memory segment. + * + * @throws SharedMemoryException + */ + private function setHeader($state, $size, $permissions) + { + if (!\is_int($state)) { + if (!(\is_bool($state) || \is_numeric($state))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($state) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($state) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $state = (int) $state; + } + } + if (!\is_int($size)) { + if (!(\is_bool($size) || \is_numeric($size))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($size) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($size) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $size = (int) $size; + } + } + if (!\is_int($permissions)) { + if (!(\is_bool($permissions) || \is_numeric($permissions))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($permissions) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($permissions) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $permissions = (int) $permissions; + } + } + $header = \pack('CLS', $state, $size, $permissions); + $this->memSet(0, $header); + } + /** + * Opens a shared memory handle. + * + * @param int $key The shared memory key. + * @param string $mode The mode to open the shared memory in. + * @param int $permissions Process permissions on the shared memory. + * @param int $size The size to crate the shared memory in bytes. + * + * @throws SharedMemoryException + */ + private function memOpen($key, $mode, $permissions, $size) + { + if (!\is_int($key)) { + if (!(\is_bool($key) || \is_numeric($key))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (int) $key; + } + } + if (!\is_string($mode)) { + if (!(\is_string($mode) || \is_object($mode) && \method_exists($mode, '__toString') || (\is_bool($mode) || \is_numeric($mode)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($mode) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $mode = (string) $mode; + } + } + if (!\is_int($permissions)) { + if (!(\is_bool($permissions) || \is_numeric($permissions))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($permissions) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($permissions) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $permissions = (int) $permissions; + } + } + if (!\is_int($size)) { + if (!(\is_bool($size) || \is_numeric($size))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($size) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($size) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $size = (int) $size; + } + } + $handle = @\shmop_open($key, $mode, $permissions, $size); + if ($handle === \false) { + $error = \error_get_last(); + throw new SharedMemoryException('Failed to create shared memory block: ' . (isset($error['message']) ? $error['message'] : 'unknown error')); + } + $this->handle = $handle; + } + /** + * Reads binary data from shared memory. + * + * @param int $offset The offset to read from. + * @param int $size The number of bytes to read. + * + * @return string The binary data at the given offset. + * + * @throws SharedMemoryException + */ + private function memGet($offset, $size) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + if (!\is_int($size)) { + if (!(\is_bool($size) || \is_numeric($size))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($size) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($size) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $size = (int) $size; + } + } + $data = \shmop_read($this->handle, $offset, $size); + if ($data === \false) { + $error = \error_get_last(); + throw new SharedMemoryException('Failed to read from shared memory block: ' . (isset($error['message']) ? $error['message'] : 'unknown error')); + } + $phabelReturn = $data; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Writes binary data to shared memory. + * + * @param int $offset The offset to write to. + * @param string $data The binary data to write. + * + * @throws SharedMemoryException + */ + private function memSet($offset, $data) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $data = (string) $data; + } + } + if (!\shmop_write($this->handle, $data, $offset)) { + $error = \error_get_last(); + throw new SharedMemoryException('Failed to write to shared memory block: ' . (isset($error['message']) ? $error['message'] : 'unknown error')); + } + } + /** + * Requests the shared memory segment to be deleted. + * + * @throws SharedMemoryException + */ + private function memDelete() + { + if (!\shmop_delete($this->handle)) { + $error = \error_get_last(); + throw new SharedMemoryException('Failed to discard shared memory block' . (isset($error['message']) ? $error['message'] : 'unknown error')); + } + } + private static function makeKey($id) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + $phabelReturn = \abs(\unpack("l", \md5($id, \true))[1]); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/SynchronizationError.php b/vendor-bundle/amphp/parallel/lib/Sync/SynchronizationError.php new file mode 100644 index 000000000..d398e1f41 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/SynchronizationError.php @@ -0,0 +1,7 @@ +mutex = new ThreadedMutex(); + $this->storage = new Internal\ParcelStorage($value); + } + /** + * {@inheritdoc} + */ + public function unwrap() + { + $phabelReturn = new Success($this->storage->get()); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return \Amp\Promise + */ + public function synchronized(callable $callback) + { + $phabelReturn = call(function () use($callback) { + /** @var \Amp\Sync\Lock $lock */ + $lock = (yield $this->mutex->acquire()); + try { + $result = (yield call($callback, $this->storage->get())); + if ($result !== null) { + $this->storage->set($result); + } + } finally { + $lock->release(); + } + return $result; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Sync/functions.php b/vendor-bundle/amphp/parallel/lib/Sync/functions.php new file mode 100644 index 000000000..a7c6601d3 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Sync/functions.php @@ -0,0 +1,146 @@ +getTrace(); + foreach ($trace as &$call) { + unset($call['object']); + $call['args'] = \array_map(__NAMESPACE__ . '\\flattenArgument', isset($call['args']) ? $call['args'] : []); + } + $phabelReturn = $trace; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * @param array $trace Backtrace produced by {@see formatFlattenedBacktrace()}. + * + * @return string + */ +function formatFlattenedBacktrace(array $trace) +{ + $output = []; + foreach ($trace as $index => $call) { + if (isset($call['class'])) { + $name = $call['class'] . $call['type'] . $call['function']; + } else { + $name = $call['function']; + } + $output[] = \sprintf('#%d %s(%d): %s(%s)', $index, isset($call['file']) ? $call['file'] : '[internal function]', isset($call['line']) ? $call['line'] : 0, $name, \implode(', ', isset($call['args']) ? $call['args'] : ['...'])); + } + $phabelReturn = \implode("\n", $output); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; +} +/** + * @param mixed $value + * + * @return string Serializable string representation of $value for backtraces. + */ +function flattenArgument($value) +{ + if ($value instanceof \Closure) { + $closureReflection = new \ReflectionFunction($value); + $phabelReturn = \sprintf('Closure(%s:%s)', $closureReflection->getFileName(), $closureReflection->getStartLine()); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (\is_object($value)) { + $phabelReturn = \sprintf('Object(%s)', \get_class($value)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (\is_array($value)) { + $phabelReturn = 'Array([' . \implode(', ', \array_map(__FUNCTION__, $value)) . '])'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (\is_resource($value)) { + $phabelReturn = \sprintf('Resource(%s)', \get_resource_type($value)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (\is_string($value)) { + $phabelReturn = '"' . $value . '"'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (\is_null($value)) { + $phabelReturn = 'null'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (\is_bool($value)) { + $phabelReturn = $value ? 'true' : 'false'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = (string) $value; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/BasicEnvironment.php b/vendor-bundle/amphp/parallel/lib/Worker/BasicEnvironment.php new file mode 100644 index 000000000..32ff7b5fb --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/BasicEnvironment.php @@ -0,0 +1,238 @@ +queue = $queue = new \SplPriorityQueue(); + $data =& $this->data; + $this->timer = Loop::repeat(1000, static function ($watcherId) use($queue, &$data) { + if (!\is_string($watcherId)) { + if (!(\is_string($watcherId) || \is_object($watcherId) && \method_exists($watcherId, '__toString') || (\is_bool($watcherId) || \is_numeric($watcherId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($watcherId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($watcherId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $watcherId = (string) $watcherId; + } + } + $time = \time(); + while (!$queue->isEmpty()) { + list($key, $expiration) = $queue->top(); + if (!isset($data[$key])) { + // Item removed. + $queue->extract(); + continue; + } + $struct = $data[$key]; + if ($struct->expire === 0) { + // Item was set again without a TTL. + $queue->extract(); + continue; + } + if ($struct->expire !== $expiration) { + // Expiration changed or TTL updated. + $queue->extract(); + continue; + } + if ($time < $struct->expire) { + // Item at top has not expired, break out of loop. + break; + } + unset($data[$key]); + $queue->extract(); + } + if ($queue->isEmpty()) { + Loop::disable($watcherId); + } + }); + Loop::disable($this->timer); + Loop::unreference($this->timer); + } + /** + * @param string $key + * + * @return bool + */ + public function exists($key) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + $phabelReturn = isset($this->data[$key]); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @param string $key + * + * @return mixed|null Returns null if the key does not exist. + */ + public function get($key) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + if (!isset($this->data[$key])) { + return null; + } + $struct = $this->data[$key]; + if ($struct->ttl !== null) { + $expire = \time() + $struct->ttl; + if ($struct->expire < $expire) { + $struct->expire = $expire; + $this->queue->insert([$key, $struct->expire], -$struct->expire); + } + } + return $struct->data; + } + /** + * @param string $key + * @param mixed $value Using null for the value deletes the key. + * @param int $ttl Number of seconds until data is automatically deleted. Use null for unlimited TTL. + * + * @throws \Error If the time-to-live is not a positive integer. + */ + public function set($key, $value, $ttl = null) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + if (!\is_null($ttl)) { + if (!\is_int($ttl)) { + if (!(\is_bool($ttl) || \is_numeric($ttl))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($ttl) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($ttl) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $ttl = (int) $ttl; + } + } + } + if ($value === null) { + $this->delete($key); + return; + } + if ($ttl !== null && $ttl <= 0) { + throw new \Error("The time-to-live must be a positive integer or null"); + } + $struct = new PhabelAnonymousClasse71fe13e24c4713755e8bf2ab3b37a7a959c11bfef39233caed7484e3f9fd4bc5(); + $struct->data = $value; + if ($ttl !== null) { + $struct->ttl = $ttl; + $struct->expire = \time() + $ttl; + $this->queue->insert([$key, $struct->expire], -$struct->expire); + Loop::enable($this->timer); + } + $this->data[$key] = $struct; + } + /** + * @param string $key + */ + public function delete($key) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + unset($this->data[$key]); + } + /** + * Alias of exists(). + * + * @param $key + * + * @return bool + */ + public function offsetExists($key) + { + $phabelReturn = $this->exists($key); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Alias of get(). + * + * @param string $key + * + * @return mixed + */ + public function offsetGet($key) + { + return $this->get($key); + } + /** + * Alias of set() with $ttl = null. + * + * @param string $key + * @param mixed $value + */ + public function offsetSet($key, $value) + { + $this->set($key, $value); + } + /** + * Alias of delete(). + * + * @param string $key + */ + public function offsetUnset($key) + { + $this->delete($key); + } + /** + * Removes all values. + */ + public function clear() + { + $this->data = []; + Loop::disable($this->timer); + $this->queue = new \SplPriorityQueue(); + } +} +if (!\class_exists(PhabelAnonymousClasse71fe13e24c4713755e8bf2ab3b37a7a959c11bfef39233caed7484e3f9fd4bc5::class)) { + class PhabelAnonymousClasse71fe13e24c4713755e8bf2ab3b37a7a959c11bfef39233caed7484e3f9fd4bc5 implements \Phabel\Target\Php70\AnonymousClass\AnonymousClassInterface + { + use Struct; + public $data; + public $expire = 0; + public $ttl; + public static function getPhabelOriginalName() + { + return 'class@anonymous'; + } + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/BootstrapWorkerFactory.php b/vendor-bundle/amphp/parallel/lib/Worker/BootstrapWorkerFactory.php new file mode 100644 index 000000000..96d0b8ffd --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/BootstrapWorkerFactory.php @@ -0,0 +1,79 @@ +bootstrapPath = $bootstrapFilePath; + $this->className = $envClassName; + } + /** + * {@inheritdoc} + * + * The type of worker created depends on the extensions available. If multi-threading is enabled, a WorkerThread + * will be created. If threads are not available a WorkerProcess will be created. + */ + public function create() + { + if (Parallel::isSupported()) { + $phabelReturn = new WorkerParallel($this->className, $this->bootstrapPath); + if (!$phabelReturn instanceof Worker) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Worker, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if (Thread::isSupported()) { + $phabelReturn = new WorkerThread($this->className, $this->bootstrapPath); + if (!$phabelReturn instanceof Worker) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Worker, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = new WorkerProcess($this->className, [], \getenv("AMP_PHP_BINARY") ?: (\defined("AMP_PHP_BINARY") ? \AMP_PHP_BINARY : null), $this->bootstrapPath); + if (!$phabelReturn instanceof Worker) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Worker, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/CallableTask.php b/vendor-bundle/amphp/parallel/lib/Worker/CallableTask.php new file mode 100644 index 000000000..786f1b075 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/CallableTask.php @@ -0,0 +1,41 @@ +callable = $callable; + $this->args = $args; + } + public function run(Environment $environment) + { + if ($this->callable instanceof \__PHP_Incomplete_Class) { + throw new \Error('When using a class instance as a callable, the class must be autoloadable'); + } + if (\is_array($this->callable) && (isset($this->callable[0]) ? $this->callable[0] : null) instanceof \__PHP_Incomplete_Class) { + throw new \Error('When using a class instance method as a callable, the class must be autoloadable'); + } + if (!\is_callable($this->callable)) { + $message = 'User-defined functions must be autoloadable (that is, defined in a file autoloaded by composer)'; + if (\is_string($this->callable)) { + $message .= \sprintf("; unable to load function '%s'", $this->callable); + } + throw new \Error($message); + } + $phabel_d75a561f64a41f7d = $this->callable; + return $phabel_d75a561f64a41f7d(...$this->args); + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/DefaultPool.php b/vendor-bundle/amphp/parallel/lib/Worker/DefaultPool.php new file mode 100644 index 000000000..724fae551 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/DefaultPool.php @@ -0,0 +1,294 @@ +maxSize = $maxSize; + // Use the global factory if none is given. + $this->factory = $factory ?: factory(); + $this->workers = new \SplObjectStorage(); + $this->idleWorkers = new \SplQueue(); + $this->busyQueue = new \SplQueue(); + $workers = $this->workers; + $idleWorkers = $this->idleWorkers; + $busyQueue = $this->busyQueue; + $this->push = static function (Worker $worker) use($workers, $idleWorkers, $busyQueue) { + if (!$workers->contains($worker) || ($workers[$worker] -= 1) > 0) { + return; + } + // Worker is completely idle, remove from busy queue and add to idle queue. + foreach ($busyQueue as $key => $busy) { + if ($busy === $worker) { + unset($busyQueue[$key]); + break; + } + } + $idleWorkers->push($worker); + }; + } + public function __destruct() + { + if ($this->isRunning()) { + $this->kill(); + } + } + /** + * Checks if the pool is running. + * + * @return bool True if the pool is running, otherwise false. + */ + public function isRunning() + { + $phabelReturn = $this->running; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Checks if the pool has any idle workers. + * + * @return bool True if the pool has at least one idle worker, otherwise false. + */ + public function isIdle() + { + $phabelReturn = $this->idleWorkers->count() > 0 || $this->workers->count() === 0; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function getMaxSize() + { + $phabelReturn = $this->maxSize; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function getWorkerCount() + { + $phabelReturn = $this->workers->count(); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function getIdleWorkerCount() + { + $phabelReturn = $this->idleWorkers->count(); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Enqueues a {@see Task} to be executed by the worker pool. + * + * @param Task $task The task to enqueue. + * + * @return Promise The return value of Task::run(). + * + * @throws StatusError If the pool has been shutdown. + * @throws TaskFailureThrowable If the task throws an exception. + */ + public function enqueue(Task $task) + { + $worker = $this->pull(); + $promise = $worker->enqueue($task); + $promise->onResolve(function () use($worker) { + $phabel_952f19190862811f = $this->push; + $phabel_952f19190862811f($worker); + }); + $phabelReturn = $promise; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Shuts down the pool and all workers in it. + * + * @return Promise Array of exit status from all workers. + * + * @throws StatusError If the pool has not been started. + */ + public function shutdown() + { + if ($this->exitStatus) { + $phabelReturn = $this->exitStatus; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $this->running = \false; + $shutdowns = []; + foreach ($this->workers as $worker) { + if ($worker->isRunning()) { + $shutdowns[] = $worker->shutdown(); + } + } + $phabelReturn = $this->exitStatus = Promise\all($shutdowns); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Kills all workers in the pool and halts the worker pool. + */ + public function kill() + { + $this->running = \false; + foreach ($this->workers as $worker) { + \assert($worker instanceof Worker); + if ($worker->isRunning()) { + $worker->kill(); + } + } + } + /** + * {@inheritdoc} + */ + public function getWorker() + { + $phabelReturn = new Internal\PooledWorker($this->pull(), $this->push); + if (!$phabelReturn instanceof Worker) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Worker, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Pulls a worker from the pool. + * + * @return Worker + * @throws StatusError + */ + private function pull() + { + if (!$this->isRunning()) { + throw new StatusError("The pool was shutdown"); + } + do { + if ($this->idleWorkers->isEmpty()) { + if ($this->getWorkerCount() >= $this->maxSize) { + // All possible workers busy, so shift from head (will be pushed back onto tail below). + $worker = $this->busyQueue->shift(); + } else { + // Max worker count has not been reached, so create another worker. + $worker = $this->factory->create(); + if (!$worker->isRunning()) { + throw new WorkerException('Worker factory did not create a viable worker'); + } + $this->workers->attach($worker, 0); + break; + } + } else { + // Shift a worker off the idle queue. + $worker = $this->idleWorkers->shift(); + } + \assert($worker instanceof Worker); + if ($worker->isRunning()) { + break; + } + // Worker crashed; trigger error and remove it from the pool. + asyncCall(function () use($worker) { + try { + $code = (yield $worker->shutdown()); + \trigger_error('Worker in pool exited unexpectedly with code ' . $code, \E_USER_WARNING); + } catch (\Exception $exception) { + \trigger_error('Worker in pool crashed with exception on shutdown: ' . $exception->getMessage(), \E_USER_WARNING); + } catch (\Error $exception) { + \trigger_error('Worker in pool crashed with exception on shutdown: ' . $exception->getMessage(), \E_USER_WARNING); + } + }); + $this->workers->detach($worker); + } while (\true); + $this->busyQueue->push($worker); + $this->workers[$worker] += 1; + $phabelReturn = $worker; + if (!$phabelReturn instanceof Worker) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Worker, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/DefaultWorkerFactory.php b/vendor-bundle/amphp/parallel/lib/Worker/DefaultWorkerFactory.php new file mode 100644 index 000000000..0c5ebb561 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/DefaultWorkerFactory.php @@ -0,0 +1,65 @@ +className = $envClassName; + } + /** + * {@inheritdoc} + * + * The type of worker created depends on the extensions available. If multi-threading is enabled, a WorkerThread + * will be created. If threads are not available a WorkerProcess will be created. + */ + public function create() + { + if (Parallel::isSupported()) { + $phabelReturn = new WorkerParallel($this->className); + if (!$phabelReturn instanceof Worker) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Worker, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if (Thread::isSupported()) { + $phabelReturn = new WorkerThread($this->className); + if (!$phabelReturn instanceof Worker) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Worker, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = new WorkerProcess($this->className, [], \getenv("AMP_PHP_BINARY") ?: (\defined("AMP_PHP_BINARY") ? \AMP_PHP_BINARY : null)); + if (!$phabelReturn instanceof Worker) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Worker, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/Environment.php b/vendor-bundle/amphp/parallel/lib/Worker/Environment.php new file mode 100644 index 000000000..2b3229fac --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/Environment.php @@ -0,0 +1,33 @@ +task = $task; + $this->id = $id++; + } + public function getId() + { + $phabelReturn = $this->id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function getTask() + { + // Classes that cannot be autoloaded will be unserialized as an instance of __PHP_Incomplete_Class. + if ($this->task instanceof \__PHP_Incomplete_Class) { + throw new \Error(\sprintf("Classes implementing %s must be autoloadable by the Composer autoloader", Task::class)); + } + $phabelReturn = $this->task; + if (!$phabelReturn instanceof Task) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Task, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/Internal/PooledWorker.php b/vendor-bundle/amphp/parallel/lib/Worker/Internal/PooledWorker.php new file mode 100644 index 000000000..1584c3a13 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/Internal/PooledWorker.php @@ -0,0 +1,91 @@ +worker = $worker; + $this->push = $push; + } + /** + * Automatically pushes the worker back into the queue. + */ + public function __destruct() + { + $phabel_add02d4737e85587 = $this->push; + $phabel_add02d4737e85587($this->worker); + } + /** + * {@inheritdoc} + */ + public function isRunning() + { + $phabelReturn = $this->worker->isRunning(); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function isIdle() + { + $phabelReturn = $this->worker->isIdle(); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function enqueue(Task $task) + { + $phabelReturn = $this->worker->enqueue($task); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function shutdown() + { + $phabelReturn = $this->worker->shutdown(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function kill() + { + $this->worker->kill(); + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/Internal/TaskFailure.php b/vendor-bundle/amphp/parallel/lib/Worker/Internal/TaskFailure.php new file mode 100644 index 000000000..7f2054c22 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/Internal/TaskFailure.php @@ -0,0 +1,71 @@ +type = \get_class($exception); + $this->parent = $exception instanceof \Error ? self::PARENT_ERROR : self::PARENT_EXCEPTION; + $this->message = $exception->getMessage(); + $this->code = $exception->getCode(); + $this->trace = Sync\flattenThrowableBacktrace($exception); + if ($previous = $exception->getPrevious()) { + $this->previous = new self($id, $previous); + } + } + public function promise() + { + $phabelReturn = new Failure($this->createException()); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function createException() + { + $previous = $this->previous ? $this->previous->createException() : null; + if ($this->parent === self::PARENT_ERROR) { + $phabelReturn = new TaskFailureError($this->type, $this->message, $this->code, $this->trace, $previous); + if (!$phabelReturn instanceof TaskFailureThrowable) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type TaskFailureThrowable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = new TaskFailureException($this->type, $this->message, $this->code, $this->trace, $previous); + if (!$phabelReturn instanceof TaskFailureThrowable) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type TaskFailureThrowable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/Internal/TaskResult.php b/vendor-bundle/amphp/parallel/lib/Worker/Internal/TaskResult.php new file mode 100644 index 000000000..d83955793 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/Internal/TaskResult.php @@ -0,0 +1,44 @@ +id = $id; + } + /** + * @return string Task identifier. + */ + public function getId() + { + $phabelReturn = $this->id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return Promise Resolved with the task result or failure reason. + */ + public abstract function promise(); +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/Internal/TaskSuccess.php b/vendor-bundle/amphp/parallel/lib/Worker/Internal/TaskSuccess.php new file mode 100644 index 000000000..b83f620c6 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/Internal/TaskSuccess.php @@ -0,0 +1,41 @@ +result = $result; + } + public function promise() + { + if ($this->result instanceof \__PHP_Incomplete_Class) { + $phabelReturn = new Failure(new \Error(\sprintf("Class instances returned from %s::run() must be autoloadable by the Composer autoloader", Task::class))); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = new Success($this->result); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/Internal/WorkerProcess.php b/vendor-bundle/amphp/parallel/lib/Worker/Internal/WorkerProcess.php new file mode 100644 index 000000000..db3c75111 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/Internal/WorkerProcess.php @@ -0,0 +1,86 @@ +process = new Process($script, null, $env, $binary); + } + public function receive() + { + $phabelReturn = $this->process->receive(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function send($data) + { + $phabelReturn = $this->process->send($data); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function isRunning() + { + $phabelReturn = $this->process->isRunning(); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function start() + { + $phabelReturn = call(function () { + $result = (yield $this->process->start()); + $stdout = $this->process->getStdout(); + $stdout->unreference(); + $stderr = $this->process->getStderr(); + $stderr->unreference(); + ByteStream\pipe($stdout, ByteStream\getStdout()); + ByteStream\pipe($stderr, ByteStream\getStderr()); + return $result; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function kill() + { + if ($this->process->isRunning()) { + $this->process->kill(); + } + } + public function join() + { + $phabelReturn = $this->process->join(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/Internal/worker-process.php b/vendor-bundle/amphp/parallel/lib/Worker/Internal/worker-process.php new file mode 100644 index 000000000..90d09fdc3 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/Internal/worker-process.php @@ -0,0 +1,39 @@ +run(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +}; diff --git a/vendor-bundle/amphp/parallel/lib/Worker/Pool.php b/vendor-bundle/amphp/parallel/lib/Worker/Pool.php new file mode 100644 index 000000000..e10212934 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/Pool.php @@ -0,0 +1,39 @@ +name = $name; + $this->trace = $trace; + } + /** + * @deprecated Use TaskFailureThrowable::getOriginalClassName() instead. + * + * Returns the class name of the error thrown from the task. + * + * @return string + */ + public function getName() + { + $phabelReturn = $this->name; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @deprecated Use TaskFailureThrowable::getOriginalTraceAsString() instead. + * + * Gets the stack trace at the point the error was thrown in the task. + * + * @return string + */ + public function getWorkerTrace() + { + $phabelReturn = $this->trace; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/TaskException.php b/vendor-bundle/amphp/parallel/lib/Worker/TaskException.php new file mode 100644 index 000000000..d45e19cd1 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/TaskException.php @@ -0,0 +1,88 @@ +name = $name; + $this->trace = $trace; + } + /** + * @deprecated Use TaskFailureThrowable::getOriginalClassName() instead. + * + * Returns the class name of the exception thrown from the task. + * + * @return string + */ + public function getName() + { + $phabelReturn = $this->name; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @deprecated Use TaskFailureThrowable::getOriginalTraceAsString() instead. + * + * Gets the stack trace at the point the exception was thrown in the task. + * + * @return string + */ + public function getWorkerTrace() + { + $phabelReturn = $this->trace; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/TaskFailureError.php b/vendor-bundle/amphp/parallel/lib/Worker/TaskFailureError.php new file mode 100644 index 000000000..c75a8ceeb --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/TaskFailureError.php @@ -0,0 +1,117 @@ +originalMessage = $message; + $this->originalCode = $code; + $this->originalTrace = $trace; + } + /** + * @return string Original exception class name. + */ + public function getOriginalClassName() + { + $phabelReturn = $this->getName(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return string Original exception message. + */ + public function getOriginalMessage() + { + $phabelReturn = $this->originalMessage; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return int|string Original exception code. + */ + public function getOriginalCode() + { + return $this->originalCode; + } + /** + * Returns the original exception stack trace. + * + * @return array Same as {@see Throwable::getTrace()}, except all function arguments are formatted as strings. + */ + public function getOriginalTrace() + { + $phabelReturn = $this->originalTrace; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Original backtrace flattened to a human-readable string. + * + * @return string + */ + public function getOriginalTraceAsString() + { + $phabelReturn = $this->getWorkerTrace(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/TaskFailureException.php b/vendor-bundle/amphp/parallel/lib/Worker/TaskFailureException.php new file mode 100644 index 000000000..1d6988f56 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/TaskFailureException.php @@ -0,0 +1,117 @@ +originalMessage = $message; + $this->originalCode = $code; + $this->originalTrace = $trace; + } + /** + * @return string Original exception class name. + */ + public function getOriginalClassName() + { + $phabelReturn = $this->getName(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return string Original exception message. + */ + public function getOriginalMessage() + { + $phabelReturn = $this->originalMessage; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return int|string Original exception code. + */ + public function getOriginalCode() + { + return $this->originalCode; + } + /** + * Returns the original exception stack trace. + * + * @return array Same as {@see Throwable::getTrace()}, except all function arguments are formatted as strings. + */ + public function getOriginalTrace() + { + $phabelReturn = $this->originalTrace; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Original backtrace flattened to a human-readable string. + * + * @return string + */ + public function getOriginalTraceAsString() + { + $phabelReturn = $this->getWorkerTrace(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/TaskFailureThrowable.php b/vendor-bundle/amphp/parallel/lib/Worker/TaskFailureThrowable.php new file mode 100644 index 000000000..3faa7b65e --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/TaskFailureThrowable.php @@ -0,0 +1,34 @@ +channel = $channel; + $this->environment = $environment; + } + /** + * Runs the task runner, receiving tasks from the parent and sending the result of those tasks. + * + * @return \Amp\Promise + */ + public function run() + { + $phabelReturn = new Coroutine($this->execute()); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @coroutine + * + * @return \Generator + */ + private function execute() + { + $job = (yield $this->channel->receive()); + while ($job instanceof Internal\Job) { + try { + $result = (yield call([$job->getTask(), "run"], $this->environment)); + $result = new Internal\TaskSuccess($job->getId(), $result); + } catch (\Exception $exception) { + $result = new Internal\TaskFailure($job->getId(), $exception); + } catch (\Error $exception) { + $result = new Internal\TaskFailure($job->getId(), $exception); + } + $job = null; + // Free memory from last job. + try { + (yield $this->channel->send($result)); + } catch (SerializationException $exception) { + // Could not serialize task result. + (yield $this->channel->send(new Internal\TaskFailure($result->getId(), $exception))); + } + $result = null; + // Free memory from last result. + $job = (yield $this->channel->receive()); + } + return $job; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/TaskWorker.php b/vendor-bundle/amphp/parallel/lib/Worker/TaskWorker.php new file mode 100644 index 000000000..c10938650 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/TaskWorker.php @@ -0,0 +1,218 @@ +isRunning()) { + throw new \Error("The context was already running"); + } + $this->context = $context; + $context =& $this->context; + $pending =& $this->pending; + \register_shutdown_function(static function () use(&$context, &$pending) { + if ($context === null || !$context->isRunning()) { + return; + } + try { + Promise\wait(Promise\timeout(call(function () use($context, $pending) { + if ($pending) { + (yield $pending); + } + (yield $context->send(0)); + return (yield $context->join()); + }), self::SHUTDOWN_TIMEOUT)); + } catch (\Exception $exception) { + if ($context !== null) { + $context->kill(); + } + } catch (\Error $exception) { + if ($context !== null) { + $context->kill(); + } + } + }); + } + /** + * {@inheritdoc} + */ + public function isRunning() + { + $phabelReturn = !$this->started || $this->exitStatus === null && $this->context !== null && $this->context->isRunning(); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + // Report as running unless shutdown or crashed. + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function isIdle() + { + $phabelReturn = $this->pending === null; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function enqueue(Task $task) + { + if ($this->exitStatus) { + throw new StatusError("The worker has been shut down"); + } + $promise = $this->pending = call(function () use($task) { + if ($this->pending) { + try { + (yield $this->pending); + } catch (\Exception $exception) { + // Ignore error from prior job. + } catch (\Error $exception) { + // Ignore error from prior job. + } + } + if ($this->exitStatus !== null || $this->context === null) { + throw new WorkerException("The worker was shutdown"); + } + if (!$this->context->isRunning()) { + if ($this->started) { + throw new WorkerException("The worker crashed"); + } + $this->started = \true; + (yield $this->context->start()); + } + $job = new Internal\Job($task); + try { + (yield $this->context->send($job)); + $result = (yield $this->context->receive()); + } catch (ChannelException $exception) { + try { + (yield Promise\timeout($this->context->join(), self::ERROR_TIMEOUT)); + } catch (TimeoutException $timeout) { + $this->kill(); + throw new WorkerException("The worker failed unexpectedly", 0, $exception); + } + throw new WorkerException("The worker exited unexpectedly", 0, $exception); + } + if (!$result instanceof Internal\TaskResult) { + $this->kill(); + throw new WorkerException("Context did not return a task result"); + } + if ($result->getId() !== $job->getId()) { + $this->kill(); + throw new WorkerException("Task results returned out of order"); + } + return $result->promise(); + }); + $promise->onResolve(function () use($promise) { + if ($this->pending === $promise) { + $this->pending = null; + } + }); + $phabelReturn = $promise; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function shutdown() + { + if ($this->exitStatus !== null) { + $phabelReturn = $this->exitStatus; + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->context === null || !$this->context->isRunning()) { + $phabelReturn = $this->exitStatus = new Success(-1); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + // Context crashed? + } + $phabelReturn = $this->exitStatus = call(function () { + if ($this->pending) { + // If a task is currently running, wait for it to finish. + (yield Promise\any([$this->pending])); + } + (yield $this->context->send(0)); + try { + return (yield Promise\timeout($this->context->join(), self::SHUTDOWN_TIMEOUT)); + } catch (\Exception $exception) { + $this->context->kill(); + throw new WorkerException("Failed to gracefully shutdown worker", 0, $exception); + } catch (\Error $exception) { + $this->context->kill(); + throw new WorkerException("Failed to gracefully shutdown worker", 0, $exception); + } finally { + // Null properties to free memory because the shutdown function has references to these. + $this->context = null; + $this->pending = null; + } + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function kill() + { + if ($this->exitStatus !== null || $this->context === null) { + return; + } + if ($this->context->isRunning()) { + $this->context->kill(); + $this->exitStatus = new Failure(new WorkerException("The worker was killed")); + return; + } + $this->exitStatus = new Success(0); + // Null properties to free memory because the shutdown function has references to these. + $this->context = null; + $this->pending = null; + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/Worker.php b/vendor-bundle/amphp/parallel/lib/Worker/Worker.php new file mode 100644 index 000000000..2f61a043c --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/Worker.php @@ -0,0 +1,41 @@ + Resolves with the return value of {@see Task::run()}. + * + * @throws TaskFailureThrowable Promise fails if {@see Task::run()} throws an exception. + */ + public function enqueue(Task $task); + /** + * @return Promise Resolves with the worker exit code. + */ + public function shutdown(); + /** + * Immediately kills the context. + */ + public function kill(); +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/WorkerException.php b/vendor-bundle/amphp/parallel/lib/Worker/WorkerException.php new file mode 100644 index 000000000..44eccab72 --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/WorkerException.php @@ -0,0 +1,7 @@ +bindTo(null, null); + // Include file within unbound closure to protect scope. + $phabel_6af5a9d497f5ab37(); + } + if (!\class_exists($className)) { + throw new \Error(\sprintf("Invalid environment class name '%s'", $className)); + } + if (!\is_subclass_of($className, Environment::class)) { + throw new \Error(\sprintf("The class '%s' does not implement '%s'", $className, Environment::class)); + } + $environment = new $className(); + if (!\defined("AMP_WORKER")) { + \define("AMP_WORKER", \AMP_CONTEXT); + } + $runner = new TaskRunner($channel, $environment); + $phabelReturn = $runner->run(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + }, $envClassName, $bootstrapPath)); + } +} diff --git a/vendor-bundle/amphp/parallel/lib/Worker/functions.php b/vendor-bundle/amphp/parallel/lib/Worker/functions.php new file mode 100644 index 000000000..1131c24cf --- /dev/null +++ b/vendor-bundle/amphp/parallel/lib/Worker/functions.php @@ -0,0 +1,115 @@ + + */ +function enqueue(Task $task) +{ + $phabelReturn = pool()->enqueue($task); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Enqueues a callable to be executed by the global worker pool. + * + * @param callable $callable Callable needs to be serializable. + * @param mixed ...$args Arguments have to be serializable. + * + * @return Promise + */ +function enqueueCallable(callable $callable, ...$args) +{ + return enqueue(new CallableTask($callable, $args)); +} +/** + * Gets a worker from the global worker pool. + * + * @return \Amp\Parallel\Worker\Worker + */ +function worker() +{ + $phabelReturn = pool()->getWorker(); + if (!$phabelReturn instanceof Worker) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Worker, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Creates a worker using the global worker factory. + * + * @return \Amp\Parallel\Worker\Worker + */ +function create() +{ + $phabelReturn = factory()->create(); + if (!$phabelReturn instanceof Worker) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Worker, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Gets or sets the global worker factory. + * + * @param WorkerFactory|null $factory + * + * @return WorkerFactory + */ +function factory(WorkerFactory $factory = null) +{ + if ($factory === null) { + $factory = Loop::getState(LOOP_FACTORY_IDENTIFIER); + if ($factory) { + $phabelReturn = $factory; + if (!$phabelReturn instanceof WorkerFactory) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type WorkerFactory, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $factory = new DefaultWorkerFactory(); + } + Loop::setState(LOOP_FACTORY_IDENTIFIER, $factory); + $phabelReturn = $factory; + if (!$phabelReturn instanceof WorkerFactory) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type WorkerFactory, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} diff --git a/vendor-bundle/amphp/parser/docs/Gemfile b/vendor-bundle/amphp/parser/docs/Gemfile new file mode 100644 index 000000000..ada6383b0 --- /dev/null +++ b/vendor-bundle/amphp/parser/docs/Gemfile @@ -0,0 +1,5 @@ +source "https://rubygems.org" +gem "github-pages" +gem "kramdown" +gem "jekyll-github-metadata" +gem "jekyll-relative-links" diff --git a/vendor-bundle/amphp/parser/docs/Gemfile.lock b/vendor-bundle/amphp/parser/docs/Gemfile.lock new file mode 100644 index 000000000..16e7a614c --- /dev/null +++ b/vendor-bundle/amphp/parser/docs/Gemfile.lock @@ -0,0 +1,202 @@ +GEM + remote: https://rubygems.org/ + specs: + activesupport (4.2.8) + i18n (~> 0.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + addressable (2.5.1) + public_suffix (~> 2.0, >= 2.0.2) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.12.2) + colorator (1.1.0) + ethon (0.10.1) + ffi (>= 1.3.0) + execjs (2.7.0) + faraday (0.12.1) + multipart-post (>= 1.2, < 3) + ffi (1.9.18) + forwardable-extended (2.6.0) + gemoji (3.0.0) + github-pages (139) + activesupport (= 4.2.8) + github-pages-health-check (= 1.3.3) + jekyll (= 3.4.3) + jekyll-avatar (= 0.4.2) + jekyll-coffeescript (= 1.0.1) + jekyll-default-layout (= 0.1.4) + jekyll-feed (= 0.9.2) + jekyll-gist (= 1.4.0) + jekyll-github-metadata (= 2.3.1) + jekyll-mentions (= 1.2.0) + jekyll-optional-front-matter (= 0.1.2) + jekyll-paginate (= 1.1.0) + jekyll-readme-index (= 0.1.0) + jekyll-redirect-from (= 0.12.1) + jekyll-relative-links (= 0.4.0) + jekyll-sass-converter (= 1.5.0) + jekyll-seo-tag (= 2.2.3) + jekyll-sitemap (= 1.0.0) + jekyll-swiss (= 0.4.0) + jekyll-theme-architect (= 0.0.4) + jekyll-theme-cayman (= 0.0.4) + jekyll-theme-dinky (= 0.0.4) + jekyll-theme-hacker (= 0.0.4) + jekyll-theme-leap-day (= 0.0.4) + jekyll-theme-merlot (= 0.0.4) + jekyll-theme-midnight (= 0.0.4) + jekyll-theme-minimal (= 0.0.4) + jekyll-theme-modernist (= 0.0.4) + jekyll-theme-primer (= 0.2.1) + jekyll-theme-slate (= 0.0.4) + jekyll-theme-tactile (= 0.0.4) + jekyll-theme-time-machine (= 0.0.4) + jekyll-titles-from-headings (= 0.1.5) + jemoji (= 0.8.0) + kramdown (= 1.13.2) + liquid (= 3.0.6) + listen (= 3.0.6) + mercenary (~> 0.3) + minima (= 2.1.1) + rouge (= 1.11.1) + terminal-table (~> 1.4) + github-pages-health-check (1.3.3) + addressable (~> 2.3) + net-dns (~> 0.8) + octokit (~> 4.0) + public_suffix (~> 2.0) + typhoeus (~> 0.7) + html-pipeline (2.6.0) + activesupport (>= 2) + nokogiri (>= 1.4) + i18n (0.8.4) + jekyll (3.4.3) + addressable (~> 2.4) + colorator (~> 1.0) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 1.1) + kramdown (~> 1.3) + liquid (~> 3.0) + mercenary (~> 0.3.3) + pathutil (~> 0.9) + rouge (~> 1.7) + safe_yaml (~> 1.0) + jekyll-avatar (0.4.2) + jekyll (~> 3.0) + jekyll-coffeescript (1.0.1) + coffee-script (~> 2.2) + jekyll-default-layout (0.1.4) + jekyll (~> 3.0) + jekyll-feed (0.9.2) + jekyll (~> 3.3) + jekyll-gist (1.4.0) + octokit (~> 4.2) + jekyll-github-metadata (2.3.1) + jekyll (~> 3.1) + octokit (~> 4.0, != 4.4.0) + jekyll-mentions (1.2.0) + activesupport (~> 4.0) + html-pipeline (~> 2.3) + jekyll (~> 3.0) + jekyll-optional-front-matter (0.1.2) + jekyll (~> 3.0) + jekyll-paginate (1.1.0) + jekyll-readme-index (0.1.0) + jekyll (~> 3.0) + jekyll-redirect-from (0.12.1) + jekyll (~> 3.3) + jekyll-relative-links (0.4.0) + jekyll (~> 3.3) + jekyll-sass-converter (1.5.0) + sass (~> 3.4) + jekyll-seo-tag (2.2.3) + jekyll (~> 3.3) + jekyll-sitemap (1.0.0) + jekyll (~> 3.3) + jekyll-swiss (0.4.0) + jekyll-theme-architect (0.0.4) + jekyll (~> 3.3) + jekyll-theme-cayman (0.0.4) + jekyll (~> 3.3) + jekyll-theme-dinky (0.0.4) + jekyll (~> 3.3) + jekyll-theme-hacker (0.0.4) + jekyll (~> 3.3) + jekyll-theme-leap-day (0.0.4) + jekyll (~> 3.3) + jekyll-theme-merlot (0.0.4) + jekyll (~> 3.3) + jekyll-theme-midnight (0.0.4) + jekyll (~> 3.3) + jekyll-theme-minimal (0.0.4) + jekyll (~> 3.3) + jekyll-theme-modernist (0.0.4) + jekyll (~> 3.3) + jekyll-theme-primer (0.2.1) + jekyll (~> 3.3) + jekyll-theme-slate (0.0.4) + jekyll (~> 3.3) + jekyll-theme-tactile (0.0.4) + jekyll (~> 3.3) + jekyll-theme-time-machine (0.0.4) + jekyll (~> 3.3) + jekyll-titles-from-headings (0.1.5) + jekyll (~> 3.3) + jekyll-watch (1.5.0) + listen (~> 3.0, < 3.1) + jemoji (0.8.0) + activesupport (~> 4.0) + gemoji (~> 3.0) + html-pipeline (~> 2.2) + jekyll (>= 3.0) + kramdown (1.13.2) + liquid (3.0.6) + listen (3.0.6) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9.7) + mercenary (0.3.6) + mini_portile2 (2.2.0) + minima (2.1.1) + jekyll (~> 3.3) + minitest (5.10.2) + multipart-post (2.0.0) + net-dns (0.8.0) + nokogiri (1.8.0) + mini_portile2 (~> 2.2.0) + octokit (4.7.0) + sawyer (~> 0.8.0, >= 0.5.3) + pathutil (0.14.0) + forwardable-extended (~> 2.6) + public_suffix (2.0.5) + rb-fsevent (0.9.8) + rb-inotify (0.9.8) + ffi (>= 0.5.0) + rouge (1.11.1) + safe_yaml (1.0.4) + sass (3.4.24) + sawyer (0.8.1) + addressable (>= 2.3.5, < 2.6) + faraday (~> 0.8, < 1.0) + terminal-table (1.8.0) + unicode-display_width (~> 1.1, >= 1.1.1) + thread_safe (0.3.6) + typhoeus (0.8.0) + ethon (>= 0.8.0) + tzinfo (1.2.3) + thread_safe (~> 0.1) + unicode-display_width (1.2.1) + +PLATFORMS + ruby + +DEPENDENCIES + github-pages + jekyll-github-metadata + jekyll-relative-links + kramdown + +BUNDLED WITH + 1.15.0 diff --git a/vendor-bundle/amphp/parser/docs/_config.yml b/vendor-bundle/amphp/parser/docs/_config.yml new file mode 100644 index 000000000..086f15010 --- /dev/null +++ b/vendor-bundle/amphp/parser/docs/_config.yml @@ -0,0 +1,23 @@ +kramdown: + input: GFM + toc_levels: 2..3 + +baseurl: "/parser" +layouts_dir: ".shared/layout" + +exclude: ["Gemfile", "Gemfile.lock", "README.md", "vendor"] +include: [".shared"] + +repository: amphp/parser +gems: + - "jekyll-github-metadata" + - "jekyll-relative-links" + +defaults: + - scope: + path: "" + type: "pages" + values: + layout: "docs" + +asset_path: "/parser/.shared/asset" diff --git a/vendor-bundle/amphp/parser/lib/InvalidDelimiterError.php b/vendor-bundle/amphp/parser/lib/InvalidDelimiterError.php new file mode 100644 index 000000000..b17a91251 --- /dev/null +++ b/vendor-bundle/amphp/parser/lib/InvalidDelimiterError.php @@ -0,0 +1,34 @@ +current(); + $prefix .= \sprintf("; %s yielded at key %s", \is_object($yielded) ? \get_class($yielded) : \gettype($yielded), \var_export($generator->key(), \true)); + if (!$generator->valid()) { + parent::__construct($prefix, 0, $previous); + return; + } + $reflGen = new \ReflectionGenerator($generator); + $exeGen = $reflGen->getExecutingGenerator(); + if ($isSubgenerator = $exeGen !== $generator) { + $reflGen = new \ReflectionGenerator($exeGen); + } + parent::__construct(\sprintf("%s on line %s in %s", $prefix, $reflGen->getExecutingLine(), $reflGen->getExecutingFile()), 0, $previous); + } +} diff --git a/vendor-bundle/amphp/parser/lib/Parser.php b/vendor-bundle/amphp/parser/lib/Parser.php new file mode 100644 index 000000000..dfeb53e4c --- /dev/null +++ b/vendor-bundle/amphp/parser/lib/Parser.php @@ -0,0 +1,129 @@ +generator = $generator; + $this->delimiter = $this->generator->current(); + if (!$this->generator->valid()) { + $this->generator = null; + return; + } + if ($this->delimiter !== null && (!\is_int($this->delimiter) || $this->delimiter <= 0) && (!\is_string($this->delimiter) || !\strlen($this->delimiter))) { + throw new InvalidDelimiterError($generator, \sprintf("Invalid value yielded: Expected NULL, an int greater than 0, or a non-empty string; %s given", \is_object($this->delimiter) ? \sprintf("instance of %s", \get_class($this->delimiter)) : \gettype($this->delimiter))); + } + } + /** + * Cancels the generator parser and returns any remaining data in the internal buffer. Writing data after calling + * this method will result in an error. + * + * @return string + */ + public final function cancel() + { + $this->generator = null; + $phabelReturn = $this->buffer; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return bool True if the parser can still receive more data to parse, false if it has ended and calling push + * will throw an exception. + */ + public final function isValid() + { + $phabelReturn = $this->generator !== null; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Adds data to the internal buffer and tries to continue parsing. + * + * @param string $data Data to append to the internal buffer. + * + * @throws InvalidDelimiterError If the generator yields an invalid delimiter. + * @throws \Error If parsing has already been cancelled. + * @throws \Throwable If the generator throws. + */ + public final function push($data) + { + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $data = (string) $data; + } + } + if ($this->generator === null) { + throw new \Error("The parser is no longer writable"); + } + $this->buffer .= $data; + $end = \false; + try { + while ($this->buffer !== "") { + if (\is_int($this->delimiter)) { + if (\strlen($this->buffer) < $this->delimiter) { + break; + // Too few bytes in buffer. + } + $send = \substr($this->buffer, 0, $this->delimiter); + $this->buffer = \substr($this->buffer, $this->delimiter); + } elseif (\is_string($this->delimiter)) { + if (($position = \strpos($this->buffer, $this->delimiter)) === \false) { + break; + } + $send = \substr($this->buffer, 0, $position); + $this->buffer = \substr($this->buffer, $position + \strlen($this->delimiter)); + } else { + $send = $this->buffer; + $this->buffer = ""; + } + $this->delimiter = $this->generator->send($send); + if (!$this->generator->valid()) { + $end = \true; + break; + } + if ($this->delimiter !== null && (!\is_int($this->delimiter) || $this->delimiter <= 0) && (!\is_string($this->delimiter) || !\strlen($this->delimiter))) { + throw new InvalidDelimiterError($this->generator, \sprintf("Invalid value yielded: Expected NULL, an int greater than 0, or a non-empty string; %s given", \is_object($this->delimiter) ? \sprintf("instance of %s", \get_class($this->delimiter)) : \gettype($this->delimiter))); + } + } + } catch (\Exception $exception) { + $end = \true; + throw $exception; + } catch (\Error $exception) { + $end = \true; + throw $exception; + } finally { + if ($end) { + $this->generator = null; + } + } + } +} diff --git a/vendor-bundle/amphp/process/appveyor.yml b/vendor-bundle/amphp/process/appveyor.yml new file mode 100644 index 000000000..9768cc702 --- /dev/null +++ b/vendor-bundle/amphp/process/appveyor.yml @@ -0,0 +1,41 @@ +build: false +shallow_clone: false + +platform: + - x86 + - x64 + +clone_folder: c:\Phabel\projects\amphp + +cache: + - c:\Phabel\tools\php74 -> appveyor.yml + +init: + - SET PATH=C:\Program Phabel\Files\OpenSSL;c:\Phabel\tools\php74;%PATH% + - SET COMPOSER_NO_INTERACTION=1 + - SET PHP=1 + - SET ANSICON=121x90 (121x90) + +install: + - IF EXIST c:\Phabel\tools\php74 (SET PHP=0) + - IF %PHP%==1 sc config wuauserv start= auto + - IF %PHP%==1 net start wuauserv + - IF %PHP%==1 cinst -y OpenSSL.Light + - IF %PHP%==1 cinst -y php + - cd c:\Phabel\tools\php74 + - IF %PHP%==1 copy php.ini-production php.ini /Y + - IF %PHP%==1 echo date.timezone="UTC" >> php.ini + - IF %PHP%==1 echo extension_dir=ext >> php.ini + - IF %PHP%==1 echo extension=php_openssl.dll >> php.ini + - IF %PHP%==1 echo extension=php_mbstring.dll >> php.ini + - IF %PHP%==1 echo extension=php_fileinfo.dll >> php.ini + - cd c:\Phabel\projects\amphp + - appveyor DownloadFile https://getcomposer.org/composer.phar + - php composer.phar install --prefer-dist --no-progress + +test_script: + - cd c:\Phabel\projects\amphp + - phpdbg -qrr vendor/phpunit/phpunit/phpunit --colors=always --coverage-text --coverage-clover build/logs/clover.xml + # Disable for now, because it can't be combined and files can't be shown on coveralls.io + # https://github.com/php-coveralls/php-coveralls/issues/234 + # - vendor/bin/coveralls -v diff --git a/vendor-bundle/amphp/process/bin/windows/ProcessWrapper.exe b/vendor-bundle/amphp/process/bin/windows/ProcessWrapper.exe new file mode 100644 index 000000000..a0a31ef5b Binary files /dev/null and b/vendor-bundle/amphp/process/bin/windows/ProcessWrapper.exe differ diff --git a/vendor-bundle/amphp/process/bin/windows/ProcessWrapper64.exe b/vendor-bundle/amphp/process/bin/windows/ProcessWrapper64.exe new file mode 100644 index 000000000..4d66f2826 Binary files /dev/null and b/vendor-bundle/amphp/process/bin/windows/ProcessWrapper64.exe differ diff --git a/vendor-bundle/amphp/process/lib/Internal/Posix/Handle.php b/vendor-bundle/amphp/process/lib/Internal/Posix/Handle.php new file mode 100644 index 000000000..2a32a1b6a --- /dev/null +++ b/vendor-bundle/amphp/process/lib/Internal/Posix/Handle.php @@ -0,0 +1,28 @@ +pidDeferred = new Deferred(); + $this->joinDeferred = new Deferred(); + $this->originalParentPid = \getmypid(); + } + /** @var Deferred */ + public $joinDeferred; + /** @var resource */ + public $proc; + /** @var resource */ + public $extraDataPipe; + /** @var string */ + public $extraDataPipeWatcher; + /** @var string */ + public $extraDataPipeStartWatcher; + /** @var int */ + public $originalParentPid; +} diff --git a/vendor-bundle/amphp/process/lib/Internal/Posix/Runner.php b/vendor-bundle/amphp/process/lib/Internal/Posix/Runner.php new file mode 100644 index 000000000..b10c048d6 --- /dev/null +++ b/vendor-bundle/amphp/process/lib/Internal/Posix/Runner.php @@ -0,0 +1,255 @@ +extraDataPipeWatcher = null; + $handle->status = ProcessStatus::ENDED; + if (!\is_resource($stream) || \feof($stream)) { + $handle->joinDeferred->fail(new ProcessException("Process ended unexpectedly")); + } else { + $handle->joinDeferred->resolve((int) \rtrim(@\stream_get_contents($stream))); + } + } + public static function onProcessStartExtraDataPipeReadable($watcher, $stream, $data) + { + Loop::cancel($watcher); + $pid = \rtrim(@\fgets($stream)); + /** @var $deferreds Deferred[] */ + list($handle, $pipes, $deferreds) = $data; + if (!$pid || !\is_numeric($pid)) { + $error = new ProcessException("Could not determine PID"); + $handle->pidDeferred->fail($error); + foreach ($deferreds as $deferred) { + /** @var $deferred Deferred */ + $deferred->fail($error); + } + if ($handle->status < ProcessStatus::ENDED) { + $handle->status = ProcessStatus::ENDED; + $handle->joinDeferred->fail($error); + } + return; + } + $handle->status = ProcessStatus::RUNNING; + $handle->pidDeferred->resolve((int) $pid); + $deferreds[0]->resolve($pipes[0]); + $deferreds[1]->resolve($pipes[1]); + $deferreds[2]->resolve($pipes[2]); + if ($handle->extraDataPipeWatcher !== null) { + Loop::enable($handle->extraDataPipeWatcher); + } + } + /** @inheritdoc */ + public function start($command, $cwd = null, array $env = [], array $options = []) + { + if (!\is_string($command)) { + if (!(\is_string($command) || \is_object($command) && \method_exists($command, '__toString') || (\is_bool($command) || \is_numeric($command)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($command) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($command) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $command = (string) $command; + } + } + if (!\is_null($cwd)) { + if (!\is_string($cwd)) { + if (!(\is_string($cwd) || \is_object($cwd) && \method_exists($cwd, '__toString') || (\is_bool($cwd) || \is_numeric($cwd)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($cwd) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cwd) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cwd = (string) $cwd; + } + } + } + $command = \sprintf('{ (%s) <&3 3<&- 3>/dev/null & } 3<&0; trap "" INT TERM QUIT HUP;pid=$!; echo $pid >&3; wait $pid; RC=$?; echo $RC >&3; exit $RC', $command); + $handle = new Handle(); + $handle->proc = @\proc_open($command, $this->generateFds(), $pipes, $cwd ?: null, $env ?: null, $options); + if (!\is_resource($handle->proc)) { + $message = "Could not start process"; + if ($error = \error_get_last()) { + $message .= \sprintf(" Errno: %d; %s", $error["type"], $error["message"]); + } + throw new ProcessException($message); + } + $status = \proc_get_status($handle->proc); + if (!$status) { + \proc_close($handle->proc); + throw new ProcessException("Could not get process status"); + } + $stdinDeferred = new Deferred(); + $handle->stdin = new ProcessOutputStream($stdinDeferred->promise()); + $stdoutDeferred = new Deferred(); + $handle->stdout = new ProcessInputStream($stdoutDeferred->promise()); + $stderrDeferred = new Deferred(); + $handle->stderr = new ProcessInputStream($stderrDeferred->promise()); + $handle->extraDataPipe = $pipes[3]; + \stream_set_blocking($pipes[3], \false); + $handle->extraDataPipeStartWatcher = Loop::onReadable($pipes[3], [self::class, 'onProcessStartExtraDataPipeReadable'], [$handle, [new ResourceOutputStream($pipes[0]), new ResourceInputStream($pipes[1]), new ResourceInputStream($pipes[2])], [$stdinDeferred, $stdoutDeferred, $stderrDeferred]]); + $handle->extraDataPipeWatcher = Loop::onReadable($pipes[3], [self::class, 'onProcessEndExtraDataPipeReadable'], $handle); + Loop::unreference($handle->extraDataPipeWatcher); + Loop::disable($handle->extraDataPipeWatcher); + $phabelReturn = $handle; + if (!$phabelReturn instanceof ProcessHandle) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ProcessHandle, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function generateFds() + { + if (self::$fdPath === null) { + self::$fdPath = \file_exists("/dev/fd") ? "/dev/fd" : "/proc/self/fd"; + } + $fdList = @\scandir(self::$fdPath, \SCANDIR_SORT_NONE); + if ($fdList === \false) { + throw new ProcessException("Unable to list open file descriptors"); + } + $fdList = \array_filter($fdList, function ($path) { + if (!\is_string($path)) { + if (!(\is_string($path) || \is_object($path) && \method_exists($path, '__toString') || (\is_bool($path) || \is_numeric($path)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($path) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($path) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $path = (string) $path; + } + } + $phabelReturn = $path !== "." && $path !== ".."; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + }); + $fds = []; + foreach ($fdList as $id) { + $fds[(int) $id] = ["file", "/dev/null", "r"]; + } + $phabelReturn = self::FD_SPEC + $fds; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** @inheritdoc */ + public function join(ProcessHandle $handle) + { + /** @var Handle $handle */ + if ($handle->extraDataPipeWatcher !== null) { + Loop::reference($handle->extraDataPipeWatcher); + } + $phabelReturn = $handle->joinDeferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** @inheritdoc */ + public function kill(ProcessHandle $handle) + { + /** @var Handle $handle */ + if ($handle->extraDataPipeWatcher !== null) { + Loop::cancel($handle->extraDataPipeWatcher); + $handle->extraDataPipeWatcher = null; + } + /** @var Handle $handle */ + if ($handle->extraDataPipeStartWatcher !== null) { + Loop::cancel($handle->extraDataPipeStartWatcher); + $handle->extraDataPipeStartWatcher = null; + } + if (!\proc_terminate($handle->proc, 9)) { + // Forcefully kill the process using SIGKILL. + throw new ProcessException("Terminating process failed"); + } + $handle->pidDeferred->promise()->onResolve(function ($error, $pid) { + // The function should not call posix_kill() if $pid is null (i.e., there was an error starting the process). + if ($error) { + return; + } + // ignore errors because process not always detached + @\posix_kill($pid, 9); + }); + if ($handle->status < ProcessStatus::ENDED) { + $handle->status = ProcessStatus::ENDED; + $handle->joinDeferred->fail(new ProcessException("The process was killed")); + } + $this->free($handle); + } + /** @inheritdoc */ + public function signal(ProcessHandle $handle, $signo) + { + if (!\is_int($signo)) { + if (!(\is_bool($signo) || \is_numeric($signo))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($signo) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signo) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signo = (int) $signo; + } + } + $handle->pidDeferred->promise()->onResolve(function ($error, $pid) use($signo) { + if ($error) { + return; + } + @\posix_kill($pid, $signo); + }); + } + /** @inheritdoc */ + public function destroy(ProcessHandle $handle) + { + /** @var Handle $handle */ + if ($handle->status < ProcessStatus::ENDED && \getmypid() === $handle->originalParentPid) { + try { + $this->kill($handle); + return; + } catch (ProcessException $e) { + // ignore + } + } + $this->free($handle); + } + private function free(Handle $handle) + { + /** @var Handle $handle */ + if ($handle->extraDataPipeWatcher !== null) { + Loop::cancel($handle->extraDataPipeWatcher); + $handle->extraDataPipeWatcher = null; + } + /** @var Handle $handle */ + if ($handle->extraDataPipeStartWatcher !== null) { + Loop::cancel($handle->extraDataPipeStartWatcher); + $handle->extraDataPipeStartWatcher = null; + } + if (\is_resource($handle->extraDataPipe)) { + \fclose($handle->extraDataPipe); + } + $handle->stdin->close(); + $handle->stdout->close(); + $handle->stderr->close(); + if (\is_resource($handle->proc)) { + \proc_close($handle->proc); + } + } +} diff --git a/vendor-bundle/amphp/process/lib/Internal/ProcessHandle.php b/vendor-bundle/amphp/process/lib/Internal/ProcessHandle.php new file mode 100644 index 000000000..c9a272eec --- /dev/null +++ b/vendor-bundle/amphp/process/lib/Internal/ProcessHandle.php @@ -0,0 +1,22 @@ + Succeeds with exit code of the process or fails if the process is killed. + */ + public function join(ProcessHandle $handle); + /** + * Forcibly end the child process. + * + * @param ProcessHandle $handle The process descriptor. + * + * @throws ProcessException If terminating the process fails. + */ + public function kill(ProcessHandle $handle); + /** + * Send a signal signal to the child process. + * + * @param ProcessHandle $handle The process descriptor. + * @param int $signo Signal number to send to process. + * + * @throws ProcessException If sending the signal fails. + */ + public function signal(ProcessHandle $handle, $signo); + /** + * Release all resources held by the process handle. + * + * @param ProcessHandle $handle The process descriptor. + */ + public function destroy(ProcessHandle $handle); +} diff --git a/vendor-bundle/amphp/process/lib/Internal/ProcessStatus.php b/vendor-bundle/amphp/process/lib/Internal/ProcessStatus.php new file mode 100644 index 000000000..fac6a06c6 --- /dev/null +++ b/vendor-bundle/amphp/process/lib/Internal/ProcessStatus.php @@ -0,0 +1,14 @@ +joinDeferred = new Deferred(); + $this->pidDeferred = new Deferred(); + } + /** @var Deferred */ + public $joinDeferred; + /** @var string */ + public $exitCodeWatcher; + /** @var bool */ + public $exitCodeRequested = \false; + /** @var resource */ + public $proc; + /** @var int */ + public $wrapperPid; + /** @var resource */ + public $wrapperStderrPipe; + /** @var resource[] */ + public $sockets = []; + /** @var Deferred[] */ + public $stdioDeferreds; + /** @var string */ + public $childPidWatcher; + /** @var string */ + public $connectTimeoutWatcher; + /** @var string[] */ + public $securityTokens; +} diff --git a/vendor-bundle/amphp/process/lib/Internal/Windows/HandshakeStatus.php b/vendor-bundle/amphp/process/lib/Internal/Windows/HandshakeStatus.php new file mode 100644 index 000000000..4e2b2db44 --- /dev/null +++ b/vendor-bundle/amphp/process/lib/Internal/Windows/HandshakeStatus.php @@ -0,0 +1,21 @@ +socketConnector->address, $this->socketConnector->port, SocketConnector::SECURITY_TOKEN_SIZE); + if ($workingDirectory !== '') { + $result .= ' ' . \escapeshellarg('--cwd=' . \rtrim($workingDirectory, '\\')); + } + $phabelReturn = $result; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function __construct() + { + $this->socketConnector = new SocketConnector(); + } + /** @inheritdoc */ + public function start($command, $cwd = null, array $env = [], array $options = []) + { + if (!\is_string($command)) { + if (!(\is_string($command) || \is_object($command) && \method_exists($command, '__toString') || (\is_bool($command) || \is_numeric($command)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($command) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($command) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $command = (string) $command; + } + } + if (!\is_null($cwd)) { + if (!\is_string($cwd)) { + if (!(\is_string($cwd) || \is_object($cwd) && \method_exists($cwd, '__toString') || (\is_bool($cwd) || \is_numeric($cwd)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($cwd) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cwd) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cwd = (string) $cwd; + } + } + } + if (\strpos($command, "\x00") !== \false) { + throw new ProcessException("Can't execute commands that contain null bytes."); + } + $options['bypass_shell'] = \true; + $handle = new Handle(); + $handle->proc = @\proc_open($this->makeCommand(isset($cwd) ? $cwd : ''), self::FD_SPEC, $pipes, $cwd ?: null, $env ?: null, $options); + if (!\is_resource($handle->proc)) { + $message = "Could not start process"; + if ($error = \error_get_last()) { + $message .= \sprintf(" Errno: %d; %s", $error["type"], $error["message"]); + } + throw new ProcessException($message); + } + $status = \proc_get_status($handle->proc); + if (!$status) { + \proc_close($handle->proc); + throw new ProcessException("Could not get process status"); + } + $securityTokens = \random_bytes(SocketConnector::SECURITY_TOKEN_SIZE * 6); + $written = \fwrite($pipes[0], $securityTokens . "\x00" . $command . "\x00"); + \fclose($pipes[0]); + \fclose($pipes[1]); + if ($written !== SocketConnector::SECURITY_TOKEN_SIZE * 6 + \strlen($command) + 2) { + \fclose($pipes[2]); + \proc_close($handle->proc); + throw new ProcessException("Could not send security tokens / command to process wrapper"); + } + $handle->securityTokens = \str_split($securityTokens, SocketConnector::SECURITY_TOKEN_SIZE); + $handle->wrapperPid = $status['pid']; + $handle->wrapperStderrPipe = $pipes[2]; + $stdinDeferred = new Deferred(); + $handle->stdioDeferreds[] = $stdinDeferred; + $handle->stdin = new ProcessOutputStream($stdinDeferred->promise()); + $stdoutDeferred = new Deferred(); + $handle->stdioDeferreds[] = $stdoutDeferred; + $handle->stdout = new ProcessInputStream($stdoutDeferred->promise()); + $stderrDeferred = new Deferred(); + $handle->stdioDeferreds[] = $stderrDeferred; + $handle->stderr = new ProcessInputStream($stderrDeferred->promise()); + $this->socketConnector->registerPendingProcess($handle); + $phabelReturn = $handle; + if (!$phabelReturn instanceof ProcessHandle) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ProcessHandle, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** @inheritdoc */ + public function join(ProcessHandle $handle) + { + /** @var Handle $handle */ + $handle->exitCodeRequested = \true; + if ($handle->exitCodeWatcher !== null) { + Loop::reference($handle->exitCodeWatcher); + } + $phabelReturn = $handle->joinDeferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** @inheritdoc */ + public function kill(ProcessHandle $handle) + { + /** @var Handle $handle */ + \exec('taskkill /F /T /PID ' . $handle->wrapperPid . ' 2>&1', $output, $exitCode); + if ($exitCode) { + throw new ProcessException("Terminating process failed"); + } + $failStart = \false; + if ($handle->childPidWatcher !== null) { + Loop::cancel($handle->childPidWatcher); + $handle->childPidWatcher = null; + $handle->pidDeferred->fail(new ProcessException("The process was killed")); + $failStart = \true; + } + if ($handle->exitCodeWatcher !== null) { + Loop::cancel($handle->exitCodeWatcher); + $handle->exitCodeWatcher = null; + $handle->joinDeferred->fail(new ProcessException("The process was killed")); + } + $handle->status = ProcessStatus::ENDED; + if ($failStart || $handle->stdioDeferreds) { + $this->socketConnector->failHandleStart($handle, "The process was killed"); + } + $this->free($handle); + } + /** @inheritdoc */ + public function signal(ProcessHandle $handle, $signo) + { + if (!\is_int($signo)) { + if (!(\is_bool($signo) || \is_numeric($signo))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($signo) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signo) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signo = (int) $signo; + } + } + throw new ProcessException('Signals are not supported on Windows'); + } + /** @inheritdoc */ + public function destroy(ProcessHandle $handle) + { + /** @var Handle $handle */ + if ($handle->status < ProcessStatus::ENDED && \is_resource($handle->proc)) { + try { + $this->kill($handle); + return; + } catch (ProcessException $e) { + // ignore + } + } + $this->free($handle); + } + private function free(Handle $handle) + { + if ($handle->childPidWatcher !== null) { + Loop::cancel($handle->childPidWatcher); + $handle->childPidWatcher = null; + } + if ($handle->exitCodeWatcher !== null) { + Loop::cancel($handle->exitCodeWatcher); + $handle->exitCodeWatcher = null; + } + $handle->stdin->close(); + $handle->stdout->close(); + $handle->stderr->close(); + foreach ($handle->sockets as $socket) { + if (\is_resource($socket)) { + @\fclose($socket); + } + } + if (\is_resource($handle->wrapperStderrPipe)) { + @\fclose($handle->wrapperStderrPipe); + } + if (\is_resource($handle->proc)) { + \proc_close($handle->proc); + } + } +} diff --git a/vendor-bundle/amphp/process/lib/Internal/Windows/SignalCode.php b/vendor-bundle/amphp/process/lib/Internal/Windows/SignalCode.php new file mode 100644 index 000000000..765ea7da9 --- /dev/null +++ b/vendor-bundle/amphp/process/lib/Internal/Windows/SignalCode.php @@ -0,0 +1,19 @@ +server = \stream_socket_server(self::SERVER_SOCKET_URI, $errNo, $errStr, $flags); + if (!$this->server) { + throw new \Error("Failed to create TCP server socket for process wrapper: {$errNo}: {$errStr}"); + } + if (!\stream_set_blocking($this->server, \false)) { + throw new \Error("Failed to set server socket to non-blocking mode"); + } + list($this->address, $this->port) = \explode(':', \stream_socket_get_name($this->server, \false)); + $this->port = (int) $this->port; + Loop::unreference(Loop::onReadable($this->server, [$this, 'onServerSocketReadable'])); + } + private function failClientHandshake($socket, $code) + { + if (!\is_int($code)) { + if (!(\is_bool($code) || \is_numeric($code))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($code) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (int) $code; + } + } + \fwrite($socket, \chr(SignalCode::HANDSHAKE_ACK) . \chr($code)); + \fclose($socket); + unset($this->pendingClients[(int) $socket]); + } + public function failHandleStart(Handle $handle, $message, ...$args) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + Loop::cancel($handle->connectTimeoutWatcher); + unset($this->pendingProcesses[$handle->wrapperPid]); + foreach ($handle->sockets as $socket) { + \fclose($socket); + } + $error = new ProcessException(\vsprintf($message, $args)); + $deferreds = $handle->stdioDeferreds; + $deferreds[] = $handle->joinDeferred; + $handle->stdioDeferreds = []; + foreach ($deferreds as $deferred) { + $deferred->fail($error); + } + } + /** + * Read data from a client socket. + * + * This method cleans up internal state as appropriate. Returns null if the read fails or needs to be repeated. + * + * @param resource $socket + * @param int $length + * @param PendingSocketClient $state + * + * @return string|null + */ + private function readDataFromPendingClient($socket, $length, PendingSocketClient $state) + { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + $data = \fread($socket, $length); + if ($data === \false || $data === '') { + return null; + } + $data = $state->receivedDataBuffer . $data; + if (\strlen($data) < $length) { + $state->receivedDataBuffer = $data; + return null; + } + $state->receivedDataBuffer = ''; + Loop::cancel($state->readWatcher); + return $data; + } + public function onReadableHandshake($watcher, $socket) + { + $socketId = (int) $socket; + $pendingClient = $this->pendingClients[$socketId]; + if (null === ($data = $this->readDataFromPendingClient($socket, self::SECURITY_TOKEN_SIZE + 6, $pendingClient))) { + return; + } + $packet = \unpack('Csignal/Npid/Cstream_id/a*client_token', $data); + // validate the client's handshake + if ($packet['signal'] !== SignalCode::HANDSHAKE) { + $this->failClientHandshake($socket, HandshakeStatus::SIGNAL_UNEXPECTED); + return; + } + if ($packet['stream_id'] > 2) { + $this->failClientHandshake($socket, HandshakeStatus::INVALID_STREAM_ID); + return; + } + if (!isset($this->pendingProcesses[$packet['pid']])) { + $this->failClientHandshake($socket, HandshakeStatus::INVALID_PROCESS_ID); + return; + } + $handle = $this->pendingProcesses[$packet['pid']]; + if (isset($handle->sockets[$packet['stream_id']])) { + $this->failClientHandshake($socket, HandshakeStatus::DUPLICATE_STREAM_ID); + \trigger_error(\sprintf("%s: Received duplicate socket for process #%s stream #%d", self::class, $handle->pid, $packet['stream_id']), \E_USER_WARNING); + return; + } + if (!\hash_equals($packet['client_token'], $handle->securityTokens[$packet['stream_id']])) { + $this->failClientHandshake($socket, HandshakeStatus::INVALID_CLIENT_TOKEN); + $this->failHandleStart($handle, "Invalid client security token for stream #%d", $packet['stream_id']); + return; + } + $ackData = \chr(SignalCode::HANDSHAKE_ACK) . \chr(HandshakeStatus::SUCCESS) . $handle->securityTokens[$packet['stream_id'] + 3]; + // Unless we set the security token size so high that it won't fit in the + // buffer, this probably shouldn't ever happen unless something has gone wrong + if (\fwrite($socket, $ackData) !== self::SECURITY_TOKEN_SIZE + 2) { + unset($this->pendingClients[$socketId]); + return; + } + $pendingClient->pid = $packet['pid']; + $pendingClient->streamId = $packet['stream_id']; + $pendingClient->readWatcher = Loop::onReadable($socket, [$this, 'onReadableHandshakeAck']); + } + public function onReadableHandshakeAck($watcher, $socket) + { + $socketId = (int) $socket; + $pendingClient = $this->pendingClients[$socketId]; + // can happen if the start promise was failed + if (!isset($this->pendingProcesses[$pendingClient->pid]) || $this->pendingProcesses[$pendingClient->pid]->status === ProcessStatus::ENDED) { + \fclose($socket); + Loop::cancel($watcher); + Loop::cancel($pendingClient->timeoutWatcher); + unset($this->pendingClients[$socketId]); + return; + } + if (null === ($data = $this->readDataFromPendingClient($socket, 2, $pendingClient))) { + return; + } + Loop::cancel($pendingClient->timeoutWatcher); + unset($this->pendingClients[$socketId]); + $handle = $this->pendingProcesses[$pendingClient->pid]; + $packet = \unpack('Csignal/Cstatus', $data); + if ($packet['signal'] !== SignalCode::HANDSHAKE_ACK || $packet['status'] !== HandshakeStatus::SUCCESS) { + $this->failHandleStart($handle, "Client rejected handshake with code %d for stream #%d", $packet['status'], $pendingClient->streamId); + return; + } + $handle->sockets[$pendingClient->streamId] = $socket; + if (\count($handle->sockets) === 3) { + $handle->childPidWatcher = Loop::onReadable($handle->sockets[0], [$this, 'onReadableChildPid'], $handle); + $deferreds = $handle->stdioDeferreds; + $handle->stdioDeferreds = []; + // clear, so there's no double resolution if process spawn fails + $deferreds[0]->resolve(new ResourceOutputStream($handle->sockets[0])); + $deferreds[1]->resolve(new ResourceInputStream($handle->sockets[1])); + $deferreds[2]->resolve(new ResourceInputStream($handle->sockets[2])); + } + } + public function onReadableChildPid($watcher, $socket, Handle $handle) + { + $data = \fread($socket, 5); + if ($data === \false || $data === '') { + return; + } + Loop::cancel($handle->childPidWatcher); + Loop::cancel($handle->connectTimeoutWatcher); + $handle->childPidWatcher = null; + if (\strlen($data) !== 5) { + $this->failHandleStart($handle, 'Failed to read PID from wrapper: Received %d of 5 expected bytes', \strlen($data)); + return; + } + $packet = \unpack('Csignal/Npid', $data); + if ($packet['signal'] !== SignalCode::CHILD_PID) { + $this->failHandleStart($handle, "Failed to read PID from wrapper: Unexpected signal code %d", $packet['signal']); + return; + } + // Required, because a process might be destroyed while starting + if ($handle->status === ProcessStatus::STARTING) { + $handle->status = ProcessStatus::RUNNING; + $handle->exitCodeWatcher = Loop::onReadable($handle->sockets[0], [$this, 'onReadableExitCode'], $handle); + if (!$handle->exitCodeRequested) { + Loop::unreference($handle->exitCodeWatcher); + } + } + $handle->pidDeferred->resolve($packet['pid']); + unset($this->pendingProcesses[$handle->wrapperPid]); + } + public function onReadableExitCode($watcher, $socket, Handle $handle) + { + $data = \fread($socket, 5); + if ($data === \false || $data === '') { + return; + } + Loop::cancel($handle->exitCodeWatcher); + $handle->exitCodeWatcher = null; + if (\strlen($data) !== 5) { + $handle->status = ProcessStatus::ENDED; + $handle->joinDeferred->fail(new ProcessException(\sprintf('Failed to read exit code from wrapper: Received %d of 5 expected bytes', \strlen($data)))); + return; + } + $packet = \unpack('Csignal/Ncode', $data); + if ($packet['signal'] !== SignalCode::EXIT_CODE) { + $this->failHandleStart($handle, "Failed to read exit code from wrapper: Unexpected signal code %d", $packet['signal']); + return; + } + $handle->status = ProcessStatus::ENDED; + $handle->joinDeferred->resolve($packet['code']); + $handle->stdin->close(); + $handle->stdout->close(); + $handle->stderr->close(); + // Explicitly \fclose() sockets, as resource streams shut only one side down. + foreach ($handle->sockets as $sock) { + // Ensure socket is still open before attempting to close. + if (\is_resource($sock)) { + @\fclose($sock); + } + } + } + public function onClientSocketConnectTimeout($watcher, $socket) + { + $id = (int) $socket; + Loop::cancel($this->pendingClients[$id]->readWatcher); + unset($this->pendingClients[$id]); + \fclose($socket); + } + public function onServerSocketReadable() + { + $socket = \stream_socket_accept($this->server); + if (!\stream_set_blocking($socket, \false)) { + throw new \Error("Failed to set client socket to non-blocking mode"); + } + $pendingClient = new PendingSocketClient(); + $pendingClient->readWatcher = Loop::onReadable($socket, [$this, 'onReadableHandshake']); + $pendingClient->timeoutWatcher = Loop::delay(self::CONNECT_TIMEOUT, [$this, 'onClientSocketConnectTimeout'], $socket); + $this->pendingClients[(int) $socket] = $pendingClient; + } + public function onProcessConnectTimeout($watcher, Handle $handle) + { + $running = \is_resource($handle->proc) && \proc_get_status($handle->proc)['running']; + $error = null; + if (!$running) { + $error = \stream_get_contents($handle->wrapperStderrPipe); + } + $error = $error ?: 'Process did not connect to server before timeout elapsed'; + foreach ($handle->sockets as $socket) { + \fclose($socket); + } + $error = new ProcessException(\trim($error)); + foreach ($handle->stdioDeferreds as $deferred) { + $deferred->fail($error); + } + \fclose($handle->wrapperStderrPipe); + \proc_close($handle->proc); + $handle->joinDeferred->fail($error); + } + public function registerPendingProcess(Handle $handle) + { + // Use Loop::defer() to start the timeout only after the loop has ticked once. This prevents issues with many + // things started at once, see https://github.com/amphp/process/issues/21. + $handle->connectTimeoutWatcher = Loop::defer(function () use($handle) { + $handle->connectTimeoutWatcher = Loop::delay(self::CONNECT_TIMEOUT, [$this, 'onProcessConnectTimeout'], $handle); + }); + $this->pendingProcesses[$handle->wrapperPid] = $handle; + } +} diff --git a/vendor-bundle/amphp/process/lib/Process.php b/vendor-bundle/amphp/process/lib/Process.php new file mode 100644 index 000000000..6aa360cc9 --- /dev/null +++ b/vendor-bundle/amphp/process/lib/Process.php @@ -0,0 +1,321 @@ + $value) { + if (\is_array($value)) { + throw new \Error("\$env cannot accept array values"); + } + $envVars[(string) $key] = (string) $value; + } + $this->command = $command; + $this->cwd = $cwd; + $this->env = $envVars; + $this->options = $options; + $this->processRunner = Loop::getState(self::class); + if ($this->processRunner === null) { + $this->processRunner = IS_WINDOWS ? new WindowsProcessRunner() : new PosixProcessRunner(); + Loop::setState(self::class, $this->processRunner); + } + } + /** + * Stops the process if it is still running. + */ + public function __destruct() + { + if ($this->handle !== null) { + $this->processRunner->destroy($this->handle); + } + } + public function __clone() + { + throw new \Error("Cloning is not allowed!"); + } + /** + * Start the process. + * + * @return Promise Resolves with the PID. + * + * @throws StatusError If the process has already been started. + */ + public function start() + { + if ($this->handle) { + throw new StatusError("Process has already been started."); + } + $phabelReturn = call(function () { + $this->handle = $this->processRunner->start($this->command, $this->cwd, $this->env, $this->options); + return $this->pid = (yield $this->handle->pidDeferred->promise()); + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Wait for the process to end. + * + * @return Promise Succeeds with process exit code or fails with a ProcessException if the process is killed. + * + * @throws StatusError If the process has already been started. + */ + public function join() + { + if (!$this->handle) { + throw new StatusError("Process has not been started."); + } + $phabelReturn = $this->processRunner->join($this->handle); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Forcibly end the process. + * + * @throws StatusError If the process is not running. + * @throws ProcessException If terminating the process fails. + */ + public function kill() + { + if (!$this->isRunning()) { + throw new StatusError("Process is not running."); + } + $this->processRunner->kill($this->handle); + } + /** + * Send a signal signal to the process. + * + * @param int $signo Signal number to send to process. + * + * @throws StatusError If the process is not running. + * @throws ProcessException If sending the signal fails. + */ + public function signal($signo) + { + if (!\is_int($signo)) { + if (!(\is_bool($signo) || \is_numeric($signo))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($signo) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signo) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signo = (int) $signo; + } + } + if (!$this->isRunning()) { + throw new StatusError("Process is not running."); + } + $this->processRunner->signal($this->handle, $signo); + } + /** + * Returns the PID of the child process. + * + * @return int + * + * @throws StatusError If the process has not started or has not completed starting. + */ + public function getPid() + { + if (!$this->pid) { + throw new StatusError("Process has not been started or has not completed starting."); + } + $phabelReturn = $this->pid; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Returns the command to execute. + * + * @return string The command to execute. + */ + public function getCommand() + { + $phabelReturn = $this->command; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the current working directory. + * + * @return string The current working directory an empty string if inherited from the current PHP process. + */ + public function getWorkingDirectory() + { + if ($this->cwd === "") { + $phabelReturn = \getcwd() ?: ""; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = $this->cwd; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the environment variables array. + * + * @return string[] Array of environment variables. + */ + public function getEnv() + { + $phabelReturn = $this->env; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Gets the options to pass to proc_open(). + * + * @return mixed[] Array of options. + */ + public function getOptions() + { + $phabelReturn = $this->options; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Determines if the process is still running. + * + * @return bool + */ + public function isRunning() + { + $phabelReturn = $this->handle && $this->handle->status !== ProcessStatus::ENDED; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the process input stream (STDIN). + * + * @return ProcessOutputStream + */ + public function getStdin() + { + if (!$this->handle || $this->handle->status === ProcessStatus::STARTING) { + throw new StatusError("Process has not been started or has not completed starting."); + } + $phabelReturn = $this->handle->stdin; + if (!$phabelReturn instanceof ProcessOutputStream) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ProcessOutputStream, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Gets the process output stream (STDOUT). + * + * @return ProcessInputStream + */ + public function getStdout() + { + if (!$this->handle || $this->handle->status === ProcessStatus::STARTING) { + throw new StatusError("Process has not been started or has not completed starting."); + } + $phabelReturn = $this->handle->stdout; + if (!$phabelReturn instanceof ProcessInputStream) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ProcessInputStream, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Gets the process error stream (STDERR). + * + * @return ProcessInputStream + */ + public function getStderr() + { + if (!$this->handle || $this->handle->status === ProcessStatus::STARTING) { + throw new StatusError("Process has not been started or has not completed starting."); + } + $phabelReturn = $this->handle->stderr; + if (!$phabelReturn instanceof ProcessInputStream) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ProcessInputStream, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function __debugInfo() + { + $phabelReturn = ['command' => $this->getCommand(), 'cwd' => $this->getWorkingDirectory(), 'env' => $this->getEnv(), 'options' => $this->getOptions(), 'pid' => $this->pid, 'status' => $this->handle ? $this->handle->status : -1]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/process/lib/ProcessException.php b/vendor-bundle/amphp/process/lib/ProcessException.php new file mode 100644 index 000000000..bd4c6e9f5 --- /dev/null +++ b/vendor-bundle/amphp/process/lib/ProcessException.php @@ -0,0 +1,7 @@ +onResolve(function ($error, $resourceStream) { + if ($error) { + $this->error = new StreamException("Failed to launch process", 0, $error); + if ($this->initialRead) { + $initialRead = $this->initialRead; + $this->initialRead = null; + $initialRead->fail($this->error); + } + return; + } + $this->resourceStream = $resourceStream; + if (!$this->referenced) { + $this->resourceStream->unreference(); + } + if ($this->shouldClose) { + $this->resourceStream->close(); + } + if ($this->initialRead) { + $initialRead = $this->initialRead; + $this->initialRead = null; + $initialRead->resolve($this->shouldClose ? null : $this->resourceStream->read()); + } + }); + } + /** + * Reads data from the stream. + * + * @return Promise Resolves with a string when new data is available or `null` if the stream has closed. + * + * @throws PendingReadError Thrown if another read operation is still pending. + */ + public function read() + { + if ($this->initialRead) { + throw new PendingReadError(); + } + if ($this->error) { + $phabelReturn = new Failure($this->error); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->resourceStream) { + $phabelReturn = $this->resourceStream->read(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->shouldClose) { + $phabelReturn = new Success(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + // Resolve reads on closed streams with null. + } + $this->initialRead = new Deferred(); + $phabelReturn = $this->initialRead->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function reference() + { + $this->referenced = \true; + if ($this->resourceStream) { + $this->resourceStream->reference(); + } + } + public function unreference() + { + $this->referenced = \false; + if ($this->resourceStream) { + $this->resourceStream->unreference(); + } + } + public function close() + { + $this->shouldClose = \true; + if ($this->initialRead) { + $initialRead = $this->initialRead; + $this->initialRead = null; + $initialRead->resolve(); + } + if ($this->resourceStream) { + $this->resourceStream->close(); + } + } +} diff --git a/vendor-bundle/amphp/process/lib/ProcessOutputStream.php b/vendor-bundle/amphp/process/lib/ProcessOutputStream.php new file mode 100644 index 000000000..1f93ce9e6 --- /dev/null +++ b/vendor-bundle/amphp/process/lib/ProcessOutputStream.php @@ -0,0 +1,132 @@ +queuedWrites = new \SplQueue(); + $resourceStreamPromise->onResolve(function ($error, $resourceStream) { + if ($error) { + $this->error = new StreamException("Failed to launch process", 0, $error); + while (!$this->queuedWrites->isEmpty()) { + list(, $deferred) = $this->queuedWrites->shift(); + $deferred->fail($this->error); + } + return; + } + while (!$this->queuedWrites->isEmpty()) { + /** + * @var string $data + * @var \Amp\Deferred $deferred + */ + list($data, $deferred) = $this->queuedWrites->shift(); + $deferred->resolve($resourceStream->write($data)); + } + $this->resourceStream = $resourceStream; + if ($this->shouldClose) { + $this->resourceStream->close(); + } + }); + } + /** @inheritdoc */ + public function write($data) + { + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $data = (string) $data; + } + } + if ($this->resourceStream) { + $phabelReturn = $this->resourceStream->write($data); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->error) { + $phabelReturn = new Failure($this->error); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->shouldClose) { + throw new ClosedException("Stream has already been closed."); + } + $deferred = new Deferred(); + $this->queuedWrites->push([$data, $deferred]); + $phabelReturn = $deferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** @inheritdoc */ + public function end($finalData = "") + { + if (!\is_string($finalData)) { + if (!(\is_string($finalData) || \is_object($finalData) && \method_exists($finalData, '__toString') || (\is_bool($finalData) || \is_numeric($finalData)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($finalData) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($finalData) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $finalData = (string) $finalData; + } + } + if ($this->resourceStream) { + $phabelReturn = $this->resourceStream->end($finalData); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->error) { + $phabelReturn = new Failure($this->error); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->shouldClose) { + throw new ClosedException("Stream has already been closed."); + } + $deferred = new Deferred(); + $this->queuedWrites->push([$finalData, $deferred]); + $this->shouldClose = \true; + $phabelReturn = $deferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function close() + { + $this->shouldClose = \true; + if ($this->resourceStream) { + $this->resourceStream->close(); + } elseif (!$this->queuedWrites->isEmpty()) { + $error = new ClosedException("Stream closed."); + do { + list(, $deferred) = $this->queuedWrites->shift(); + $deferred->fail($error); + } while (!$this->queuedWrites->isEmpty()); + } + } +} diff --git a/vendor-bundle/amphp/process/lib/StatusError.php b/vendor-bundle/amphp/process/lib/StatusError.php new file mode 100644 index 000000000..4570392ae --- /dev/null +++ b/vendor-bundle/amphp/process/lib/StatusError.php @@ -0,0 +1,7 @@ +serializer = $serializer; + } + public function serialize($data) + { + $serializedData = $this->serializer->serialize($data); + $flags = 0; + if (\strlen($serializedData) > self::COMPRESSION_THRESHOLD) { + $serializedData = @\gzdeflate($serializedData, 1); + if ($serializedData === \false) { + $error = \error_get_last(); + throw new SerializationException('Could not compress data: ' . (isset($error['message']) ? $error['message'] : 'unknown error')); + } + $flags |= self::FLAG_COMPRESSED; + } + $phabelReturn = \chr($flags & 0xff) . $serializedData; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function unserialize($data) + { + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $data = (string) $data; + } + } + $firstByte = \ord($data[0]); + $data = \substr($data, 1); + if ($firstByte & self::FLAG_COMPRESSED) { + $data = @\gzinflate($data); + if ($data === \false) { + $error = \error_get_last(); + throw new SerializationException('Could not decompress data: ' . (isset($error['message']) ? $error['message'] : 'unknown error')); + } + } + return $this->serializer->unserialize($data); + } +} diff --git a/vendor-bundle/amphp/serialization/src/JsonSerializer.php b/vendor-bundle/amphp/serialization/src/JsonSerializer.php new file mode 100644 index 000000000..9e699a9b2 --- /dev/null +++ b/vendor-bundle/amphp/serialization/src/JsonSerializer.php @@ -0,0 +1,165 @@ +associative = $associative; + $this->depth = $depth; + // We don't want to throw on errors, we manually check for errors using json_last_error(). + $this->encodeOptions = $encodeOptions & ~self::THROW_ON_ERROR; + $this->decodeOptions = $decodeOptions & ~self::THROW_ON_ERROR; + } + public function serialize($data) + { + $result = \json_encode($data, $this->encodeOptions, $this->depth); + switch ($code = \json_last_error()) { + case \JSON_ERROR_NONE: + $phabelReturn = $result; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + default: + throw new SerializationException(\json_last_error_msg(), $code); + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + public function unserialize($data) + { + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $data = (string) $data; + } + } + $result = \json_decode($data, $this->associative, $this->depth, $this->decodeOptions); + switch ($code = \json_last_error()) { + case \JSON_ERROR_NONE: + return $result; + default: + throw new SerializationException(\json_last_error_msg(), $code); + } + } +} diff --git a/vendor-bundle/amphp/serialization/src/NativeSerializer.php b/vendor-bundle/amphp/serialization/src/NativeSerializer.php new file mode 100644 index 000000000..2230cbd37 --- /dev/null +++ b/vendor-bundle/amphp/serialization/src/NativeSerializer.php @@ -0,0 +1,59 @@ +allowedClasses = $allowedClasses; + } + public function serialize($data) + { + try { + $phabelReturn = \serialize($data); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } catch (\Exception $exception) { + throw new SerializationException(\sprintf('The given data could not be serialized: %s', $exception->getMessage()), 0, $exception); + } catch (\Error $exception) { + throw new SerializationException(\sprintf('The given data could not be serialized: %s', $exception->getMessage()), 0, $exception); + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + public function unserialize($data) + { + if (!\is_string($data)) { + if (!(\is_string($data) || \is_object($data) && \method_exists($data, '__toString') || (\is_bool($data) || \is_numeric($data)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($data) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($data) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $data = (string) $data; + } + } + try { + $result = \unserialize($data, ['allowed_classes' => isset($this->allowedClasses) ? $this->allowedClasses : \true]); + if ($result === \false && $data !== \serialize(\false)) { + throw new SerializationException('Invalid data provided to unserialize: ' . encodeUnprintableChars($data)); + } + } catch (\Exception $exception) { + throw new SerializationException('Exception thrown when unserializing data', 0, $exception); + } catch (\Error $exception) { + throw new SerializationException('Exception thrown when unserializing data', 0, $exception); + } + return $result; + } +} diff --git a/vendor-bundle/amphp/serialization/src/PassthroughSerializer.php b/vendor-bundle/amphp/serialization/src/PassthroughSerializer.php new file mode 100644 index 000000000..7b88eb2cd --- /dev/null +++ b/vendor-bundle/amphp/serialization/src/PassthroughSerializer.php @@ -0,0 +1,41 @@ +arrive(); + * $barrier->arrive(); // promise returned from Barrier::await() is now resolved + * + * yield $barrier->await(); + * ``` + */ +final class Barrier +{ + /** @var int */ + private $count; + /** @var Deferred */ + private $deferred; + public function __construct($count) + { + if (!\is_int($count)) { + if (!(\is_bool($count) || \is_numeric($count))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($count) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($count) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $count = (int) $count; + } + } + if ($count < 1) { + throw new \Error('Count must be positive, got ' . $count); + } + $this->count = $count; + $this->deferred = new Deferred(); + } + public function getCount() + { + $phabelReturn = $this->count; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + public function arrive($count = 1) + { + if (!\is_int($count)) { + if (!(\is_bool($count) || \is_numeric($count))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($count) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($count) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $count = (int) $count; + } + } + if ($count < 1) { + throw new \Error('Count must be at least 1, got ' . $count); + } + if ($count > $this->count) { + throw new \Error('Count cannot be greater than remaining count: ' . $count . ' > ' . $this->count); + } + $this->count -= $count; + if ($this->count === 0) { + $this->deferred->resolve(); + } + } + public function register($count = 1) + { + if (!\is_int($count)) { + if (!(\is_bool($count) || \is_numeric($count))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($count) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($count) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $count = (int) $count; + } + } + if ($count < 1) { + throw new \Error('Count must be at least 1, got ' . $count); + } + if ($this->count === 0) { + throw new \Error('Can\'t increase count, because the barrier already broke'); + } + $this->count += $count; + } + public function await() + { + $phabelReturn = $this->deferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/sync/src/ConcurrentIterator/functions.php b/vendor-bundle/amphp/sync/src/ConcurrentIterator/functions.php new file mode 100644 index 000000000..c551718e3 --- /dev/null +++ b/vendor-bundle/amphp/sync/src/ConcurrentIterator/functions.php @@ -0,0 +1,165 @@ +getId()]); + $lock->release(); + $barrier->arrive(); + } + }; + while ((yield $iterator->advance())) { + if ($error) { + break; + } + /** @var Lock $lock */ + $lock = (yield $semaphore->acquire()); + if ($gc || isset($locks[$lock->getId()])) { + // Throwing here causes a segfault on PHP 7.3 + return; + // throw new CancelledException; // producer and locks have been GCed + } + $locks[$lock->getId()] = \true; + $barrier->register(); + asyncCall($processor, $lock, $iterator->getCurrent()); + } + $barrier->arrive(); + // remove dummy item + (yield $barrier->await()); + if ($error) { + throw $error; + } + }); + if (!$phabelReturn instanceof Iterator) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Iterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Concurrently map all iterator values using {@code $processor}. + * + * The order of the items in the resulting iterator is not guaranteed in any way. + * + * @param Iterator $iterator Values to map. + * @param Semaphore $semaphore Semaphore limiting the concurrency, e.g. {@code LocalSemaphore} + * @param callable $processor Processing callable, which is run as coroutine. It should not throw any errors, + * otherwise the entire operation is aborted. + * + * @return Iterator Mapped values. + */ +function map(Iterator $iterator, Semaphore $semaphore, callable $processor) +{ + $processor = coroutine($processor); + $phabelReturn = transform($iterator, $semaphore, static function ($value, callable $emit) use($processor) { + $value = (yield $processor($value)); + (yield $emit($value)); + }); + if (!$phabelReturn instanceof Iterator) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Iterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Concurrently filter all iterator values using {@code $filter}. + * + * The order of the items in the resulting iterator is not guaranteed in any way. + * + * @param Iterator $iterator Values to map. + * @param Semaphore $semaphore Semaphore limiting the concurrency, e.g. {@code LocalSemaphore} + * @param callable $filter Processing callable, which is run as coroutine. It should not throw any errors, + * otherwise the entire operation is aborted. Must resolve to a boolean, true to keep values in the resulting + * iterator. + * + * @return Iterator Values, where {@code $filter} resolved to {@code true}. + */ +function filter(Iterator $iterator, Semaphore $semaphore, callable $filter) +{ + $filter = coroutine($filter); + $phabelReturn = transform($iterator, $semaphore, static function ($value, callable $emit) use($filter) { + $keep = (yield $filter($value)); + if (!\is_bool($keep)) { + throw new \TypeError(__NAMESPACE__ . '\\filter\'s callable must resolve to a boolean value, got ' . \gettype($keep)); + } + if ($keep) { + (yield $emit($value)); + } + }); + if (!$phabelReturn instanceof Iterator) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Iterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} +/** + * Concurrently invoke a callback on all iterator values using {@code $processor}. + * + * @param Iterator $iterator Values to act on. + * @param Semaphore $semaphore Semaphore limiting the concurrency, e.g. {@code LocalSemaphore} + * @param callable $processor Processing callable, which is run as coroutine. It should not throw any errors, + * otherwise the entire operation is aborted. + * + * @return Promise + */ +function each(Iterator $iterator, Semaphore $semaphore, callable $processor) +{ + $processor = coroutine($processor); + $iterator = transform($iterator, $semaphore, static function ($value, callable $emit) use($processor) { + (yield $processor($value)); + (yield $emit(null)); + }); + $phabelReturn = call(static function () use($iterator) { + $count = 0; + while ((yield $iterator->advance())) { + $count++; + } + return $count; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // Use Amp\Iterator\discard in the future + return $phabelReturn; +} diff --git a/vendor-bundle/amphp/sync/src/FileMutex.php b/vendor-bundle/amphp/sync/src/FileMutex.php new file mode 100644 index 000000000..28617ab25 --- /dev/null +++ b/vendor-bundle/amphp/sync/src/FileMutex.php @@ -0,0 +1,84 @@ +fileName = $fileName; + } + /** + * {@inheritdoc} + */ + public function acquire() + { + $phabelReturn = new Coroutine($this->doAcquire()); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @coroutine + * + * @return \Generator + */ + private function doAcquire() + { + // Try to create the lock file. If the file already exists, someone else + // has the lock, so set an asynchronous timer and try again. + while (($handle = @\fopen($this->fileName, 'x')) === \false) { + (yield new Delayed(self::LATENCY_TIMEOUT)); + } + // Return a lock object that can be used to release the lock on the mutex. + $lock = new Lock(0, function () { + $this->release(); + }); + \fclose($handle); + return $lock; + } + /** + * Releases the lock on the mutex. + * + * @throws SyncException If the unlock operation failed. + */ + protected function release() + { + $success = @\unlink($this->fileName); + if (!$success) { + throw new SyncException('Failed to unlock the mutex file.'); + } + } +} diff --git a/vendor-bundle/amphp/sync/src/Internal/MutexStorage.php b/vendor-bundle/amphp/sync/src/Internal/MutexStorage.php new file mode 100644 index 000000000..528d0558e --- /dev/null +++ b/vendor-bundle/amphp/sync/src/Internal/MutexStorage.php @@ -0,0 +1,53 @@ +locked) { + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $this->locked = \true; + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + }; + while ($this->locked || $this->synchronized($tsl)) { + (yield new Delayed(self::LATENCY_TIMEOUT)); + } + return new Lock(0, function () { + $this->locked = \false; + }); + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/sync/src/Internal/SemaphoreStorage.php b/vendor-bundle/amphp/sync/src/Internal/SemaphoreStorage.php new file mode 100644 index 000000000..25bb534bc --- /dev/null +++ b/vendor-bundle/amphp/sync/src/Internal/SemaphoreStorage.php @@ -0,0 +1,86 @@ +count()) { + $phabelReturn = null; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + $phabelReturn = $this->shift(); + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + }; + while (!$this->count() || ($id = $this->synchronized($tsl)) === null) { + (yield new Delayed(self::LATENCY_TIMEOUT)); + } + return new Lock($id, function (Lock $lock) { + $id = $lock->getId(); + $this->synchronized(function () use($id) { + $this[] = $id; + }); + }); + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** + * Uses a double locking mechanism to acquire a lock without blocking. A + * synchronous mutex is used to make sure that the semaphore is queried one + * at a time to preserve the integrity of the semaphore itself. Then a lock + * count is used to check if a lock is available without blocking. + * + * If a lock is not available, we add the request to a queue and set a timer + * to check again in the future. + */ + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/sync/src/KeyedMutex.php b/vendor-bundle/amphp/sync/src/KeyedMutex.php new file mode 100644 index 000000000..a578d8193 --- /dev/null +++ b/vendor-bundle/amphp/sync/src/KeyedMutex.php @@ -0,0 +1,14 @@ +mutex[$key])) { + $this->mutex[$key] = new LocalMutex(); + $this->locks[$key] = 0; + } + $phabelReturn = call(function () use($key) { + $this->locks[$key]++; + /** @var Lock $lock */ + $lock = (yield $this->mutex[$key]->acquire()); + return new Lock(0, function () use($lock, $key) { + if (--$this->locks[$key] === 0) { + unset($this->mutex[$key], $this->locks[$key]); + } + $lock->release(); + }); + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/sync/src/LocalKeyedSemaphore.php b/vendor-bundle/amphp/sync/src/LocalKeyedSemaphore.php new file mode 100644 index 000000000..e559f1186 --- /dev/null +++ b/vendor-bundle/amphp/sync/src/LocalKeyedSemaphore.php @@ -0,0 +1,55 @@ +maxLocks = $maxLocks; + } + public function acquire($key) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + if (!isset($this->semaphore[$key])) { + $this->semaphore[$key] = new LocalSemaphore($this->maxLocks); + $this->locks[$key] = 0; + } + $phabelReturn = call(function () use($key) { + $this->locks[$key]++; + /** @var Lock $lock */ + $lock = (yield $this->semaphore[$key]->acquire()); + return new Lock(0, function () use($lock, $key) { + if (--$this->locks[$key] === 0) { + unset($this->semaphore[$key], $this->locks[$key]); + } + $lock->release(); + }); + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/sync/src/LocalMutex.php b/vendor-bundle/amphp/sync/src/LocalMutex.php new file mode 100644 index 000000000..6013eeb4b --- /dev/null +++ b/vendor-bundle/amphp/sync/src/LocalMutex.php @@ -0,0 +1,44 @@ +locked) { + $this->locked = \true; + $phabelReturn = new Success(new Lock(0, \Phabel\Target\Php71\ClosureFromCallable::fromCallable([$this, 'release']))); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $this->queue[] = $deferred = new Deferred(); + $phabelReturn = $deferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function release() + { + if (!empty($this->queue)) { + $deferred = \array_shift($this->queue); + $deferred->resolve(new Lock(0, \Phabel\Target\Php71\ClosureFromCallable::fromCallable([$this, 'release']))); + return; + } + $this->locked = \false; + } +} diff --git a/vendor-bundle/amphp/sync/src/LocalSemaphore.php b/vendor-bundle/amphp/sync/src/LocalSemaphore.php new file mode 100644 index 000000000..214eb53ea --- /dev/null +++ b/vendor-bundle/amphp/sync/src/LocalSemaphore.php @@ -0,0 +1,58 @@ +locks = \range(0, $maxLocks - 1); + } + /** {@inheritdoc} */ + public function acquire() + { + if (!empty($this->locks)) { + $phabelReturn = new Success(new Lock(\array_shift($this->locks), \Phabel\Target\Php71\ClosureFromCallable::fromCallable([$this, 'release']))); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $this->queue[] = $deferred = new Deferred(); + $phabelReturn = $deferred->promise(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function release(Lock $lock) + { + $id = $lock->getId(); + if (!empty($this->queue)) { + $deferred = \array_shift($this->queue); + $deferred->resolve(new Lock($id, \Phabel\Target\Php71\ClosureFromCallable::fromCallable([$this, 'release']))); + return; + } + $this->locks[] = $id; + } +} diff --git a/vendor-bundle/amphp/sync/src/Lock.php b/vendor-bundle/amphp/sync/src/Lock.php new file mode 100644 index 000000000..b705e45d2 --- /dev/null +++ b/vendor-bundle/amphp/sync/src/Lock.php @@ -0,0 +1,91 @@ +id = $id; + $this->releaser = $releaser; + } + /** + * Checks if the lock has already been released. + * + * @return bool True if the lock has already been released, otherwise false. + */ + public function isReleased() + { + $phabelReturn = !$this->releaser; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return int Lock identifier. + */ + public function getId() + { + $phabelReturn = $this->id; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Releases the lock. No-op if the lock has already been released. + */ + public function release() + { + if (!$this->releaser) { + return; + } + // Invoke the releaser function given to us by the synchronization source + // to release the lock. + $releaser = $this->releaser; + $this->releaser = null; + $releaser($this); + } + /** + * Releases the lock when there are no more references to it. + */ + public function __destruct() + { + if (!$this->isReleased()) { + $this->release(); + } + } +} diff --git a/vendor-bundle/amphp/sync/src/Mutex.php b/vendor-bundle/amphp/sync/src/Mutex.php new file mode 100644 index 000000000..15c963a1b --- /dev/null +++ b/vendor-bundle/amphp/sync/src/Mutex.php @@ -0,0 +1,14 @@ +init($maxLocks, $permissions); + $phabelReturn = $semaphore; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string $id The unique name of the semaphore to use. + * + * @return \Amp\Sync\PosixSemaphore + */ + public static function use_($id) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + $semaphore = new self($id); + $semaphore->open(); + $phabelReturn = $semaphore; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string $id + * + * @throws \Error If the sysvmsg extension is not loaded. + */ + private function __construct($id) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + if (!\extension_loaded("sysvmsg")) { + throw new \Error(__CLASS__ . " requires the sysvmsg extension."); + } + $this->id = $id; + $this->key = self::makeKey($this->id); + } + /** + * Private method to prevent cloning. + */ + private function __clone() + { + } + /** + * Private to prevent serialization. + */ + private function __sleep() + { + } + public function getId() + { + $phabelReturn = $this->id; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + private function open() + { + if (!\msg_queue_exists($this->key)) { + throw new SyncException('No semaphore with that ID found'); + } + $this->queue = \msg_get_queue($this->key); + if (!$this->queue) { + throw new SyncException('Failed to open the semaphore.'); + } + } + /** + * @param int $maxLocks The maximum number of locks that can be acquired from the semaphore. + * @param int $permissions Permissions to access the semaphore. + * + * @throws SyncException If the semaphore could not be created due to an internal error. + */ + private function init($maxLocks, $permissions) + { + if (!\is_int($maxLocks)) { + if (!(\is_bool($maxLocks) || \is_numeric($maxLocks))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($maxLocks) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($maxLocks) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $maxLocks = (int) $maxLocks; + } + } + if (!\is_int($permissions)) { + if (!(\is_bool($permissions) || \is_numeric($permissions))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($permissions) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($permissions) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $permissions = (int) $permissions; + } + } + if (\msg_queue_exists($this->key)) { + throw new SyncException('A semaphore with that ID already exists'); + } + $this->queue = \msg_get_queue($this->key, $permissions); + if (!$this->queue) { + throw new SyncException('Failed to create the semaphore.'); + } + $this->initializer = \getmypid(); + // Fill the semaphore with locks. + while (--$maxLocks >= 0) { + $this->release($maxLocks); + } + } + /** + * Gets the access permissions of the semaphore. + * + * @return int A permissions mode. + */ + public function getPermissions() + { + $stat = \msg_stat_queue($this->queue); + $phabelReturn = $stat['msg_perm.mode']; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Sets the access permissions of the semaphore. + * + * The current user must have access to the semaphore in order to change the permissions. + * + * @param int $mode A permissions mode to set. + * + * @throws SyncException If the operation failed. + */ + public function setPermissions($mode) + { + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($mode) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $mode = (int) $mode; + } + } + if (!\msg_set_queue($this->queue, ['msg_perm.mode' => $mode])) { + throw new SyncException('Failed to change the semaphore permissions.'); + } + } + public function acquire() + { + $phabelReturn = new Coroutine($this->doAcquire()); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + private function doAcquire() + { + do { + // Attempt to acquire a lock from the semaphore. + if (@\msg_receive($this->queue, 0, $type, 1, $id, \false, \MSG_IPC_NOWAIT, $errno)) { + // A free lock was found, so resolve with a lock object that can + // be used to release the lock. + return new Lock(\unpack("C", $id)[1], function (Lock $lock) { + $this->release($lock->getId()); + }); + } + // Check for unusual errors. + if ($errno !== \MSG_ENOMSG) { + throw new SyncException(\sprintf('Failed to acquire a lock; errno: %d', $errno)); + } + } while ((yield new Delayed(self::LATENCY_TIMEOUT, \true))); + } + /** + * Removes the semaphore if it still exists. + * + * @throws SyncException If the operation failed. + */ + public function __destruct() + { + if ($this->initializer === 0 || $this->initializer !== \getmypid()) { + return; + } + if (!\is_resource($this->queue) || !\msg_queue_exists($this->key)) { + return; + } + \msg_remove_queue($this->queue); + } + /** + * Releases a lock from the semaphore. + * + * @param int $id Lock identifier. + * + * @throws SyncException If the operation failed. + */ + protected function release($id) + { + if (!\is_int($id)) { + if (!(\is_bool($id) || \is_numeric($id))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (int) $id; + } + } + if (!$this->queue) { + return; + // Queue already destroyed. + } + // Call send in non-blocking mode. If the call fails because the queue + // is full, then the number of locks configured is too large. + if (!@\msg_send($this->queue, 1, \pack("C", $id), \false, \false, $errno)) { + if ($errno === \MSG_EAGAIN) { + throw new SyncException('The semaphore size is larger than the system allows.'); + } + throw new SyncException('Failed to release the lock.'); + } + } + private static function makeKey($id) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + $phabelReturn = \abs(\unpack("l", \md5($id, \true))[1]); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/sync/src/PrefixedKeyedMutex.php b/vendor-bundle/amphp/sync/src/PrefixedKeyedMutex.php new file mode 100644 index 000000000..c992dd8aa --- /dev/null +++ b/vendor-bundle/amphp/sync/src/PrefixedKeyedMutex.php @@ -0,0 +1,39 @@ +mutex = $mutex; + $this->prefix = $prefix; + } + public function acquire($key) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + $phabelReturn = $this->mutex->acquire($this->prefix . $key); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/sync/src/PrefixedKeyedSemaphore.php b/vendor-bundle/amphp/sync/src/PrefixedKeyedSemaphore.php new file mode 100644 index 000000000..086d8eb50 --- /dev/null +++ b/vendor-bundle/amphp/sync/src/PrefixedKeyedSemaphore.php @@ -0,0 +1,39 @@ +semaphore = $semaphore; + $this->prefix = $prefix; + } + public function acquire($key) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + $phabelReturn = $this->semaphore->acquire($this->prefix . $key); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/sync/src/Semaphore.php b/vendor-bundle/amphp/sync/src/Semaphore.php new file mode 100644 index 000000000..dbe59d30f --- /dev/null +++ b/vendor-bundle/amphp/sync/src/Semaphore.php @@ -0,0 +1,14 @@ +semaphore = $semaphore; + } + /** {@inheritdoc} */ + public function acquire() + { + $phabelReturn = call(function () { + /** @var \Amp\Sync\Lock $lock */ + $lock = (yield $this->semaphore->acquire()); + if ($lock->getId() !== 0) { + $lock->release(); + throw new \Error("Cannot use a semaphore with more than a single lock"); + } + return $lock; + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/sync/src/StaticKeyMutex.php b/vendor-bundle/amphp/sync/src/StaticKeyMutex.php new file mode 100644 index 000000000..fa771cf87 --- /dev/null +++ b/vendor-bundle/amphp/sync/src/StaticKeyMutex.php @@ -0,0 +1,32 @@ +mutex = $mutex; + $this->key = $key; + } + public function acquire() + { + $phabelReturn = $this->mutex->acquire($this->key); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/sync/src/SyncException.php b/vendor-bundle/amphp/sync/src/SyncException.php new file mode 100644 index 000000000..3006f958e --- /dev/null +++ b/vendor-bundle/amphp/sync/src/SyncException.php @@ -0,0 +1,7 @@ +mutex = new Internal\MutexStorage(); + } + /** + * {@inheritdoc} + */ + public function acquire() + { + $phabelReturn = $this->mutex->acquire(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/sync/src/ThreadedSemaphore.php b/vendor-bundle/amphp/sync/src/ThreadedSemaphore.php new file mode 100644 index 000000000..716d96df4 --- /dev/null +++ b/vendor-bundle/amphp/sync/src/ThreadedSemaphore.php @@ -0,0 +1,50 @@ +semaphore = new Internal\SemaphoreStorage($locks); + } + /** + * {@inheritdoc} + */ + public function acquire() + { + $phabelReturn = $this->semaphore->acquire(); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/amphp/sync/src/functions.php b/vendor-bundle/amphp/sync/src/functions.php new file mode 100644 index 000000000..185609c85 --- /dev/null +++ b/vendor-bundle/amphp/sync/src/functions.php @@ -0,0 +1,33 @@ +acquire()); + try { + return (yield call($callback, ...$args)); + } finally { + $lock->release(); + } + }); + if (!$phabelReturn instanceof Promise) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Promise, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; +} diff --git a/vendor-bundle/amphp/sync/travis/install-pcov.sh b/vendor-bundle/amphp/sync/travis/install-pcov.sh new file mode 100644 index 000000000..57c230cd9 --- /dev/null +++ b/vendor-bundle/amphp/sync/travis/install-pcov.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -e + +if [[ ${TRAVIS_PHP_VERSION:0:3} == "7.0" ]]; then + exit 0 +fi + +# required for pcov/clobber +curl -LS https://pecl.php.net/get/uopz | tar -xz \ + && pushd uopz-* \ + && phpize \ + && ./configure --enable-uopz \ + && make -j4 \ + && make install \ + && popd \ + && echo "extension=uopz.so" >> "$(php -r 'echo php_ini_loaded_file();')"; + +curl -LS https://pecl.php.net/get/pcov | tar -xz \ + && pushd pcov-* \ + && phpize \ + && ./configure --enable-pcov \ + && make \ + && make install \ + && popd \ + && echo "extension=pcov.so" >> "$(php -r 'echo php_ini_loaded_file();')"; diff --git a/vendor-bundle/amphp/sync/travis/install-pthreads.sh b/vendor-bundle/amphp/sync/travis/install-pthreads.sh new file mode 100644 index 000000000..3dca0059a --- /dev/null +++ b/vendor-bundle/amphp/sync/travis/install-pthreads.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +git clone https://github.com/krakjoe/pthreads; +pushd pthreads; +git checkout master; +phpize; +./configure; +make; +make install; +popd; +echo "extension=pthreads.so" >> "$(php -r 'echo php_ini_loaded_file();')" diff --git a/vendor-bundle/autoload.php b/vendor-bundle/autoload.php new file mode 100644 index 000000000..8332083a7 --- /dev/null +++ b/vendor-bundle/autoload.php @@ -0,0 +1,3 @@ + ['startLine', 'endLine', 'startFilePos', 'endFilePos', 'comments']]); +$parser = (new PhpParser\ParserFactory())->create(PhpParser\ParserFactory::PREFER_PHP7, $lexer); +$dumper = new PhpParser\NodeDumper(['dumpComments' => \true, 'dumpPositions' => $attributes['with-positions']]); +$prettyPrinter = new PhpParser\PrettyPrinter\Standard(); +$traverser = new PhpParser\NodeTraverser(); +$traverser->addVisitor(new PhpParser\NodeVisitor\NameResolver()); +foreach ($files as $file) { + if (\strpos($file, ' Code {$code}\n"); + } else { + if (!\file_exists($file)) { + \fwrite(\STDERR, "File {$file} does not exist.\n"); + exit(1); + } + $code = \file_get_contents($file); + \fwrite(\STDERR, "====> File {$file}:\n"); + } + if ($attributes['with-recovery']) { + $errorHandler = new PhpParser\ErrorHandler\Collecting(); + $stmts = $parser->parse($code, $errorHandler); + foreach ($errorHandler->getErrors() as $error) { + $message = formatErrorMessage($error, $code, $attributes['with-column-info']); + \fwrite(\STDERR, $message . "\n"); + } + if (null === $stmts) { + continue; + } + } else { + try { + $stmts = $parser->parse($code); + } catch (PhpParser\Error $error) { + $message = formatErrorMessage($error, $code, $attributes['with-column-info']); + \fwrite(\STDERR, $message . "\n"); + exit(1); + } + } + foreach ($operations as $operation) { + if ('dump' === $operation) { + \fwrite(\STDERR, "==> Node dump:\n"); + echo $dumper->dump($stmts, $code), "\n"; + } elseif ('pretty-print' === $operation) { + \fwrite(\STDERR, "==> Pretty print:\n"); + echo $prettyPrinter->prettyPrintFile($stmts), "\n"; + } elseif ('json-dump' === $operation) { + \fwrite(\STDERR, "==> JSON dump:\n"); + echo \json_encode($stmts, \JSON_PRETTY_PRINT), "\n"; + } elseif ('var-dump' === $operation) { + \fwrite(\STDERR, "==> var_dump():\n"); + \var_dump($stmts); + } elseif ('resolve-names' === $operation) { + \fwrite(\STDERR, "==> Resolved names.\n"); + $stmts = $traverser->traverse($stmts); + } + } +} +function formatErrorMessage(PhpParser\Error $e, $code, $withColumnInfo) +{ + if ($withColumnInfo && $e->hasColumnInfo()) { + return $e->getMessageWithColumnInfo($code); + } else { + return $e->getMessage(); + } +} +function showHelp($error = '') +{ + if ($error) { + \fwrite(\STDERR, $error . "\n\n"); + } + \fwrite($error ? \STDERR : \STDOUT, << \false, 'with-positions' => \false, 'with-recovery' => \false]; + \array_shift($args); + $parseOptions = \true; + foreach ($args as $arg) { + if (!$parseOptions) { + $files[] = $arg; + continue; + } + switch ($arg) { + case '--dump': + case '-d': + $operations[] = 'dump'; + break; + case '--pretty-print': + case '-p': + $operations[] = 'pretty-print'; + break; + case '--json-dump': + case '-j': + $operations[] = 'json-dump'; + break; + case '--var-dump': + $operations[] = 'var-dump'; + break; + case '--resolve-names': + case '-N': + $operations[] = 'resolve-names'; + break; + case '--with-column-info': + case '-c': + $attributes['with-column-info'] = \true; + break; + case '--with-positions': + case '-P': + $attributes['with-positions'] = \true; + break; + case '--with-recovery': + case '-r': + $attributes['with-recovery'] = \true; + break; + case '--help': + case '-h': + showHelp(); + break; + case '--': + $parseOptions = \false; + break; + default: + if ($arg[0] === '-') { + showHelp("Invalid operation {$arg}."); + } else { + $files[] = $arg; + } + } + } + return [$operations, $files, $attributes]; +} diff --git a/vendor-bundle/phabel/php-parser/grammar/parser.template b/vendor-bundle/phabel/php-parser/grammar/parser.template new file mode 100644 index 000000000..6166607c9 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/grammar/parser.template @@ -0,0 +1,106 @@ +semValue +#semval($,%t) $this->semValue +#semval(%n) $stackPos-(%l-%n) +#semval(%n,%t) $stackPos-(%l-%n) + +namespace PhpParser\Parser; + +use PhpParser\Error; +use PhpParser\Node; +use PhpParser\Node\Expr; +use PhpParser\Node\Name; +use PhpParser\Node\Scalar; +use PhpParser\Node\Stmt; +#include; + +/* This is an automatically GENERATED file, which should not be manually edited. + * Instead edit one of the following: + * * the grammar files grammar/php5.y or grammar/php7.y + * * the skeleton file grammar/parser.template + * * the preprocessing script grammar/rebuildParsers.php + */ +class #(-p) extends \PhpParser\ParserAbstract +{ + protected $tokenToSymbolMapSize = #(YYMAXLEX); + protected $actionTableSize = #(YYLAST); + protected $gotoTableSize = #(YYGLAST); + + protected $invalidSymbol = #(YYBADCH); + protected $errorSymbol = #(YYINTERRTOK); + protected $defaultAction = #(YYDEFAULT); + protected $unexpectedTokenRule = #(YYUNEXPECTED); + + protected $YY2TBLSTATE = #(YY2TBLSTATE); + protected $numNonLeafStates = #(YYNLSTATES); + + protected $symbolToName = array( + #listvar terminals + ); + + protected $tokenToSymbol = array( + #listvar yytranslate + ); + + protected $action = array( + #listvar yyaction + ); + + protected $actionCheck = array( + #listvar yycheck + ); + + protected $actionBase = array( + #listvar yybase + ); + + protected $actionDefault = array( + #listvar yydefault + ); + + protected $goto = array( + #listvar yygoto + ); + + protected $gotoCheck = array( + #listvar yygcheck + ); + + protected $gotoBase = array( + #listvar yygbase + ); + + protected $gotoDefault = array( + #listvar yygdefault + ); + + protected $ruleToNonTerminal = array( + #listvar yylhs + ); + + protected $ruleToLength = array( + #listvar yylen + ); +#if -t + + protected $productions = array( + #production-strings; + ); +#endif + + protected function initReduceCallbacks() { + $this->reduceCallbacks = [ +#reduce + %n => function ($stackPos) { + %b + }, +#noact + %n => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, +#endreduce + ]; + } +} +#tailcode; diff --git a/vendor-bundle/phabel/php-parser/grammar/php5.y b/vendor-bundle/phabel/php-parser/grammar/php5.y new file mode 100644 index 000000000..c7d245dc7 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/grammar/php5.y @@ -0,0 +1,1026 @@ +%pure_parser +%expect 6 + +%tokens + +%% + +start: + top_statement_list { $$ = $this->handleNamespaces($1); } +; + +top_statement_list_ex: + top_statement_list_ex top_statement { pushNormalizing($1, $2); } + | /* empty */ { init(); } +; + +top_statement_list: + top_statement_list_ex + { makeZeroLengthNop($nop, $this->lookaheadStartAttributes); + if ($nop !== null) { $1[] = $nop; } $$ = $1; } +; + +reserved_non_modifiers: + T_INCLUDE | T_INCLUDE_ONCE | T_EVAL | T_REQUIRE | T_REQUIRE_ONCE | T_LOGICAL_OR | T_LOGICAL_XOR | T_LOGICAL_AND + | T_INSTANCEOF | T_NEW | T_CLONE | T_EXIT | T_IF | T_ELSEIF | T_ELSE | T_ENDIF | T_ECHO | T_DO | T_WHILE + | T_ENDWHILE | T_FOR | T_ENDFOR | T_FOREACH | T_ENDFOREACH | T_DECLARE | T_ENDDECLARE | T_AS | T_TRY | T_CATCH + | T_FINALLY | T_THROW | T_USE | T_INSTEADOF | T_GLOBAL | T_VAR | T_UNSET | T_ISSET | T_EMPTY | T_CONTINUE | T_GOTO + | T_FUNCTION | T_CONST | T_RETURN | T_PRINT | T_YIELD | T_LIST | T_SWITCH | T_ENDSWITCH | T_CASE | T_DEFAULT + | T_BREAK | T_ARRAY | T_CALLABLE | T_EXTENDS | T_IMPLEMENTS | T_NAMESPACE | T_TRAIT | T_INTERFACE | T_CLASS + | T_CLASS_C | T_TRAIT_C | T_FUNC_C | T_METHOD_C | T_LINE | T_FILE | T_DIR | T_NS_C | T_HALT_COMPILER | T_FN + | T_MATCH +; + +semi_reserved: + reserved_non_modifiers + | T_STATIC | T_ABSTRACT | T_FINAL | T_PRIVATE | T_PROTECTED | T_PUBLIC +; + +identifier_ex: + T_STRING { $$ = Node\Identifier[$1]; } + | semi_reserved { $$ = Node\Identifier[$1]; } +; + +identifier: + T_STRING { $$ = Node\Identifier[$1]; } +; + +reserved_non_modifiers_identifier: + reserved_non_modifiers { $$ = Node\Identifier[$1]; } +; + +namespace_name: + T_STRING { $$ = Name[$1]; } + | T_NAME_QUALIFIED { $$ = Name[$1]; } +; + +legacy_namespace_name: + namespace_name { $$ = $1; } + | T_NAME_FULLY_QUALIFIED { $$ = Name[substr($1, 1)]; } +; + +plain_variable: + T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; } +; + +top_statement: + statement { $$ = $1; } + | function_declaration_statement { $$ = $1; } + | class_declaration_statement { $$ = $1; } + | T_HALT_COMPILER + { $$ = Stmt\HaltCompiler[$this->lexer->handleHaltCompiler()]; } + | T_NAMESPACE namespace_name ';' + { $$ = Stmt\Namespace_[$2, null]; + $$->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON); + $this->checkNamespace($$); } + | T_NAMESPACE namespace_name '{' top_statement_list '}' + { $$ = Stmt\Namespace_[$2, $4]; + $$->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $this->checkNamespace($$); } + | T_NAMESPACE '{' top_statement_list '}' + { $$ = Stmt\Namespace_[null, $3]; + $$->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $this->checkNamespace($$); } + | T_USE use_declarations ';' { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; } + | T_USE use_type use_declarations ';' { $$ = Stmt\Use_[$3, $2]; } + | group_use_declaration ';' { $$ = $1; } + | T_CONST constant_declaration_list ';' { $$ = Stmt\Const_[$2]; } +; + +use_type: + T_FUNCTION { $$ = Stmt\Use_::TYPE_FUNCTION; } + | T_CONST { $$ = Stmt\Use_::TYPE_CONSTANT; } +; + +group_use_declaration: + T_USE use_type legacy_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}' + { $$ = Stmt\GroupUse[$3, $6, $2]; } + | T_USE legacy_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}' + { $$ = Stmt\GroupUse[$2, $5, Stmt\Use_::TYPE_UNKNOWN]; } +; + +unprefixed_use_declarations: + unprefixed_use_declarations ',' unprefixed_use_declaration + { push($1, $3); } + | unprefixed_use_declaration { init($1); } +; + +use_declarations: + use_declarations ',' use_declaration { push($1, $3); } + | use_declaration { init($1); } +; + +inline_use_declarations: + inline_use_declarations ',' inline_use_declaration { push($1, $3); } + | inline_use_declaration { init($1); } +; + +unprefixed_use_declaration: + namespace_name + { $$ = Stmt\UseUse[$1, null, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #1); } + | namespace_name T_AS identifier + { $$ = Stmt\UseUse[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #3); } +; + +use_declaration: + legacy_namespace_name + { $$ = Stmt\UseUse[$1, null, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #1); } + | legacy_namespace_name T_AS identifier + { $$ = Stmt\UseUse[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #3); } +; + +inline_use_declaration: + unprefixed_use_declaration { $$ = $1; $$->type = Stmt\Use_::TYPE_NORMAL; } + | use_type unprefixed_use_declaration { $$ = $2; $$->type = $1; } +; + +constant_declaration_list: + constant_declaration_list ',' constant_declaration { push($1, $3); } + | constant_declaration { init($1); } +; + +constant_declaration: + identifier '=' static_scalar { $$ = Node\Const_[$1, $3]; } +; + +class_const_list: + class_const_list ',' class_const { push($1, $3); } + | class_const { init($1); } +; + +class_const: + identifier_ex '=' static_scalar { $$ = Node\Const_[$1, $3]; } +; + +inner_statement_list_ex: + inner_statement_list_ex inner_statement { pushNormalizing($1, $2); } + | /* empty */ { init(); } +; + +inner_statement_list: + inner_statement_list_ex + { makeZeroLengthNop($nop, $this->lookaheadStartAttributes); + if ($nop !== null) { $1[] = $nop; } $$ = $1; } +; + +inner_statement: + statement { $$ = $1; } + | function_declaration_statement { $$ = $1; } + | class_declaration_statement { $$ = $1; } + | T_HALT_COMPILER + { throw new Error('__HALT_COMPILER() can only be used from the outermost scope', attributes()); } +; + +non_empty_statement: + '{' inner_statement_list '}' + { + if ($2) { + $$ = $2; prependLeadingComments($$); + } else { + makeNop($$, $this->startAttributeStack[#1], $this->endAttributes); + if (null === $$) { $$ = array(); } + } + } + | T_IF parentheses_expr statement elseif_list else_single + { $$ = Stmt\If_[$2, ['stmts' => toArray($3), 'elseifs' => $4, 'else' => $5]]; } + | T_IF parentheses_expr ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';' + { $$ = Stmt\If_[$2, ['stmts' => $4, 'elseifs' => $5, 'else' => $6]]; } + | T_WHILE parentheses_expr while_statement { $$ = Stmt\While_[$2, $3]; } + | T_DO statement T_WHILE parentheses_expr ';' { $$ = Stmt\Do_ [$4, toArray($2)]; } + | T_FOR '(' for_expr ';' for_expr ';' for_expr ')' for_statement + { $$ = Stmt\For_[['init' => $3, 'cond' => $5, 'loop' => $7, 'stmts' => $9]]; } + | T_SWITCH parentheses_expr switch_case_list { $$ = Stmt\Switch_[$2, $3]; } + | T_BREAK ';' { $$ = Stmt\Break_[null]; } + | T_BREAK expr ';' { $$ = Stmt\Break_[$2]; } + | T_CONTINUE ';' { $$ = Stmt\Continue_[null]; } + | T_CONTINUE expr ';' { $$ = Stmt\Continue_[$2]; } + | T_RETURN ';' { $$ = Stmt\Return_[null]; } + | T_RETURN expr ';' { $$ = Stmt\Return_[$2]; } + | T_GLOBAL global_var_list ';' { $$ = Stmt\Global_[$2]; } + | T_STATIC static_var_list ';' { $$ = Stmt\Static_[$2]; } + | T_ECHO expr_list ';' { $$ = Stmt\Echo_[$2]; } + | T_INLINE_HTML { $$ = Stmt\InlineHTML[$1]; } + | yield_expr ';' { $$ = Stmt\Expression[$1]; } + | expr ';' { $$ = Stmt\Expression[$1]; } + | T_UNSET '(' variables_list ')' ';' { $$ = Stmt\Unset_[$3]; } + | T_FOREACH '(' expr T_AS foreach_variable ')' foreach_statement + { $$ = Stmt\Foreach_[$3, $5[0], ['keyVar' => null, 'byRef' => $5[1], 'stmts' => $7]]; } + | T_FOREACH '(' expr T_AS variable T_DOUBLE_ARROW foreach_variable ')' foreach_statement + { $$ = Stmt\Foreach_[$3, $7[0], ['keyVar' => $5, 'byRef' => $7[1], 'stmts' => $9]]; } + | T_DECLARE '(' declare_list ')' declare_statement { $$ = Stmt\Declare_[$3, $5]; } + | T_TRY '{' inner_statement_list '}' catches optional_finally + { $$ = Stmt\TryCatch[$3, $5, $6]; $this->checkTryCatch($$); } + | T_THROW expr ';' { $$ = Stmt\Throw_[$2]; } + | T_GOTO identifier ';' { $$ = Stmt\Goto_[$2]; } + | identifier ':' { $$ = Stmt\Label[$1]; } + | expr error { $$ = Stmt\Expression[$1]; } + | error { $$ = array(); /* means: no statement */ } +; + +statement: + non_empty_statement { $$ = $1; } + | ';' + { makeNop($$, $this->startAttributeStack[#1], $this->endAttributes); + if ($$ === null) $$ = array(); /* means: no statement */ } +; + +catches: + /* empty */ { init(); } + | catches catch { push($1, $2); } +; + +catch: + T_CATCH '(' name plain_variable ')' '{' inner_statement_list '}' + { $$ = Stmt\Catch_[array($3), $4, $7]; } +; + +optional_finally: + /* empty */ { $$ = null; } + | T_FINALLY '{' inner_statement_list '}' { $$ = Stmt\Finally_[$3]; } +; + +variables_list: + variable { init($1); } + | variables_list ',' variable { push($1, $3); } +; + +optional_ref: + /* empty */ { $$ = false; } + | '&' { $$ = true; } +; + +optional_ellipsis: + /* empty */ { $$ = false; } + | T_ELLIPSIS { $$ = true; } +; + +function_declaration_statement: + T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type '{' inner_statement_list '}' + { $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $9]]; } +; + +class_declaration_statement: + class_entry_type identifier extends_from implements_list '{' class_statement_list '}' + { $$ = Stmt\Class_[$2, ['type' => $1, 'extends' => $3, 'implements' => $4, 'stmts' => $6]]; + $this->checkClass($$, #2); } + | T_INTERFACE identifier interface_extends_list '{' class_statement_list '}' + { $$ = Stmt\Interface_[$2, ['extends' => $3, 'stmts' => $5]]; + $this->checkInterface($$, #2); } + | T_TRAIT identifier '{' class_statement_list '}' + { $$ = Stmt\Trait_[$2, ['stmts' => $4]]; } +; + +class_entry_type: + T_CLASS { $$ = 0; } + | T_ABSTRACT T_CLASS { $$ = Stmt\Class_::MODIFIER_ABSTRACT; } + | T_FINAL T_CLASS { $$ = Stmt\Class_::MODIFIER_FINAL; } +; + +extends_from: + /* empty */ { $$ = null; } + | T_EXTENDS class_name { $$ = $2; } +; + +interface_extends_list: + /* empty */ { $$ = array(); } + | T_EXTENDS class_name_list { $$ = $2; } +; + +implements_list: + /* empty */ { $$ = array(); } + | T_IMPLEMENTS class_name_list { $$ = $2; } +; + +class_name_list: + class_name { init($1); } + | class_name_list ',' class_name { push($1, $3); } +; + +for_statement: + statement { $$ = toArray($1); } + | ':' inner_statement_list T_ENDFOR ';' { $$ = $2; } +; + +foreach_statement: + statement { $$ = toArray($1); } + | ':' inner_statement_list T_ENDFOREACH ';' { $$ = $2; } +; + +declare_statement: + non_empty_statement { $$ = toArray($1); } + | ';' { $$ = null; } + | ':' inner_statement_list T_ENDDECLARE ';' { $$ = $2; } +; + +declare_list: + declare_list_element { init($1); } + | declare_list ',' declare_list_element { push($1, $3); } +; + +declare_list_element: + identifier '=' static_scalar { $$ = Stmt\DeclareDeclare[$1, $3]; } +; + +switch_case_list: + '{' case_list '}' { $$ = $2; } + | '{' ';' case_list '}' { $$ = $3; } + | ':' case_list T_ENDSWITCH ';' { $$ = $2; } + | ':' ';' case_list T_ENDSWITCH ';' { $$ = $3; } +; + +case_list: + /* empty */ { init(); } + | case_list case { push($1, $2); } +; + +case: + T_CASE expr case_separator inner_statement_list_ex { $$ = Stmt\Case_[$2, $4]; } + | T_DEFAULT case_separator inner_statement_list_ex { $$ = Stmt\Case_[null, $3]; } +; + +case_separator: + ':' + | ';' +; + +while_statement: + statement { $$ = toArray($1); } + | ':' inner_statement_list T_ENDWHILE ';' { $$ = $2; } +; + +elseif_list: + /* empty */ { init(); } + | elseif_list elseif { push($1, $2); } +; + +elseif: + T_ELSEIF parentheses_expr statement { $$ = Stmt\ElseIf_[$2, toArray($3)]; } +; + +new_elseif_list: + /* empty */ { init(); } + | new_elseif_list new_elseif { push($1, $2); } +; + +new_elseif: + T_ELSEIF parentheses_expr ':' inner_statement_list { $$ = Stmt\ElseIf_[$2, $4]; } +; + +else_single: + /* empty */ { $$ = null; } + | T_ELSE statement { $$ = Stmt\Else_[toArray($2)]; } +; + +new_else_single: + /* empty */ { $$ = null; } + | T_ELSE ':' inner_statement_list { $$ = Stmt\Else_[$3]; } +; + +foreach_variable: + variable { $$ = array($1, false); } + | '&' variable { $$ = array($2, true); } + | list_expr { $$ = array($1, false); } +; + +parameter_list: + non_empty_parameter_list { $$ = $1; } + | /* empty */ { $$ = array(); } +; + +non_empty_parameter_list: + parameter { init($1); } + | non_empty_parameter_list ',' parameter { push($1, $3); } +; + +parameter: + optional_param_type optional_ref optional_ellipsis plain_variable + { $$ = Node\Param[$4, null, $1, $2, $3]; $this->checkParam($$); } + | optional_param_type optional_ref optional_ellipsis plain_variable '=' static_scalar + { $$ = Node\Param[$4, $6, $1, $2, $3]; $this->checkParam($$); } +; + +type: + name { $$ = $1; } + | T_ARRAY { $$ = Node\Identifier['array']; } + | T_CALLABLE { $$ = Node\Identifier['callable']; } +; + +optional_param_type: + /* empty */ { $$ = null; } + | type { $$ = $1; } +; + +optional_return_type: + /* empty */ { $$ = null; } + | ':' type { $$ = $2; } +; + +argument_list: + '(' ')' { $$ = array(); } + | '(' non_empty_argument_list ')' { $$ = $2; } + | '(' yield_expr ')' { $$ = array(Node\Arg[$2, false, false]); } +; + +non_empty_argument_list: + argument { init($1); } + | non_empty_argument_list ',' argument { push($1, $3); } +; + +argument: + expr { $$ = Node\Arg[$1, false, false]; } + | '&' variable { $$ = Node\Arg[$2, true, false]; } + | T_ELLIPSIS expr { $$ = Node\Arg[$2, false, true]; } +; + +global_var_list: + global_var_list ',' global_var { push($1, $3); } + | global_var { init($1); } +; + +global_var: + plain_variable { $$ = $1; } + | '$' variable { $$ = Expr\Variable[$2]; } + | '$' '{' expr '}' { $$ = Expr\Variable[$3]; } +; + +static_var_list: + static_var_list ',' static_var { push($1, $3); } + | static_var { init($1); } +; + +static_var: + plain_variable { $$ = Stmt\StaticVar[$1, null]; } + | plain_variable '=' static_scalar { $$ = Stmt\StaticVar[$1, $3]; } +; + +class_statement_list_ex: + class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } } + | /* empty */ { init(); } +; + +class_statement_list: + class_statement_list_ex + { makeZeroLengthNop($nop, $this->lookaheadStartAttributes); + if ($nop !== null) { $1[] = $nop; } $$ = $1; } +; + +class_statement: + variable_modifiers property_declaration_list ';' + { $$ = Stmt\Property[$1, $2]; $this->checkProperty($$, #1); } + | T_CONST class_const_list ';' { $$ = Stmt\ClassConst[$2, 0]; } + | method_modifiers T_FUNCTION optional_ref identifier_ex '(' parameter_list ')' optional_return_type method_body + { $$ = Stmt\ClassMethod[$4, ['type' => $1, 'byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9]]; + $this->checkClassMethod($$, #1); } + | T_USE class_name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; } +; + +trait_adaptations: + ';' { $$ = array(); } + | '{' trait_adaptation_list '}' { $$ = $2; } +; + +trait_adaptation_list: + /* empty */ { init(); } + | trait_adaptation_list trait_adaptation { push($1, $2); } +; + +trait_adaptation: + trait_method_reference_fully_qualified T_INSTEADOF class_name_list ';' + { $$ = Stmt\TraitUseAdaptation\Precedence[$1[0], $1[1], $3]; } + | trait_method_reference T_AS member_modifier identifier_ex ';' + { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, $4]; } + | trait_method_reference T_AS member_modifier ';' + { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, null]; } + | trait_method_reference T_AS identifier ';' + { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; } + | trait_method_reference T_AS reserved_non_modifiers_identifier ';' + { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; } +; + +trait_method_reference_fully_qualified: + name T_PAAMAYIM_NEKUDOTAYIM identifier_ex { $$ = array($1, $3); } +; +trait_method_reference: + trait_method_reference_fully_qualified { $$ = $1; } + | identifier_ex { $$ = array(null, $1); } +; + +method_body: + ';' /* abstract method */ { $$ = null; } + | '{' inner_statement_list '}' { $$ = $2; } +; + +variable_modifiers: + non_empty_member_modifiers { $$ = $1; } + | T_VAR { $$ = 0; } +; + +method_modifiers: + /* empty */ { $$ = 0; } + | non_empty_member_modifiers { $$ = $1; } +; + +non_empty_member_modifiers: + member_modifier { $$ = $1; } + | non_empty_member_modifiers member_modifier { $this->checkModifier($1, $2, #2); $$ = $1 | $2; } +; + +member_modifier: + T_PUBLIC { $$ = Stmt\Class_::MODIFIER_PUBLIC; } + | T_PROTECTED { $$ = Stmt\Class_::MODIFIER_PROTECTED; } + | T_PRIVATE { $$ = Stmt\Class_::MODIFIER_PRIVATE; } + | T_STATIC { $$ = Stmt\Class_::MODIFIER_STATIC; } + | T_ABSTRACT { $$ = Stmt\Class_::MODIFIER_ABSTRACT; } + | T_FINAL { $$ = Stmt\Class_::MODIFIER_FINAL; } +; + +property_declaration_list: + property_declaration { init($1); } + | property_declaration_list ',' property_declaration { push($1, $3); } +; + +property_decl_name: + T_VARIABLE { $$ = Node\VarLikeIdentifier[parseVar($1)]; } +; + +property_declaration: + property_decl_name { $$ = Stmt\PropertyProperty[$1, null]; } + | property_decl_name '=' static_scalar { $$ = Stmt\PropertyProperty[$1, $3]; } +; + +expr_list: + expr_list ',' expr { push($1, $3); } + | expr { init($1); } +; + +for_expr: + /* empty */ { $$ = array(); } + | expr_list { $$ = $1; } +; + +expr: + variable { $$ = $1; } + | list_expr '=' expr { $$ = Expr\Assign[$1, $3]; } + | variable '=' expr { $$ = Expr\Assign[$1, $3]; } + | variable '=' '&' variable { $$ = Expr\AssignRef[$1, $4]; } + | variable '=' '&' new_expr { $$ = Expr\AssignRef[$1, $4]; } + | new_expr { $$ = $1; } + | T_CLONE expr { $$ = Expr\Clone_[$2]; } + | variable T_PLUS_EQUAL expr { $$ = Expr\AssignOp\Plus [$1, $3]; } + | variable T_MINUS_EQUAL expr { $$ = Expr\AssignOp\Minus [$1, $3]; } + | variable T_MUL_EQUAL expr { $$ = Expr\AssignOp\Mul [$1, $3]; } + | variable T_DIV_EQUAL expr { $$ = Expr\AssignOp\Div [$1, $3]; } + | variable T_CONCAT_EQUAL expr { $$ = Expr\AssignOp\Concat [$1, $3]; } + | variable T_MOD_EQUAL expr { $$ = Expr\AssignOp\Mod [$1, $3]; } + | variable T_AND_EQUAL expr { $$ = Expr\AssignOp\BitwiseAnd[$1, $3]; } + | variable T_OR_EQUAL expr { $$ = Expr\AssignOp\BitwiseOr [$1, $3]; } + | variable T_XOR_EQUAL expr { $$ = Expr\AssignOp\BitwiseXor[$1, $3]; } + | variable T_SL_EQUAL expr { $$ = Expr\AssignOp\ShiftLeft [$1, $3]; } + | variable T_SR_EQUAL expr { $$ = Expr\AssignOp\ShiftRight[$1, $3]; } + | variable T_POW_EQUAL expr { $$ = Expr\AssignOp\Pow [$1, $3]; } + | variable T_COALESCE_EQUAL expr { $$ = Expr\AssignOp\Coalesce [$1, $3]; } + | variable T_INC { $$ = Expr\PostInc[$1]; } + | T_INC variable { $$ = Expr\PreInc [$2]; } + | variable T_DEC { $$ = Expr\PostDec[$1]; } + | T_DEC variable { $$ = Expr\PreDec [$2]; } + | expr T_BOOLEAN_OR expr { $$ = Expr\BinaryOp\BooleanOr [$1, $3]; } + | expr T_BOOLEAN_AND expr { $$ = Expr\BinaryOp\BooleanAnd[$1, $3]; } + | expr T_LOGICAL_OR expr { $$ = Expr\BinaryOp\LogicalOr [$1, $3]; } + | expr T_LOGICAL_AND expr { $$ = Expr\BinaryOp\LogicalAnd[$1, $3]; } + | expr T_LOGICAL_XOR expr { $$ = Expr\BinaryOp\LogicalXor[$1, $3]; } + | expr '|' expr { $$ = Expr\BinaryOp\BitwiseOr [$1, $3]; } + | expr '&' expr { $$ = Expr\BinaryOp\BitwiseAnd[$1, $3]; } + | expr '^' expr { $$ = Expr\BinaryOp\BitwiseXor[$1, $3]; } + | expr '.' expr { $$ = Expr\BinaryOp\Concat [$1, $3]; } + | expr '+' expr { $$ = Expr\BinaryOp\Plus [$1, $3]; } + | expr '-' expr { $$ = Expr\BinaryOp\Minus [$1, $3]; } + | expr '*' expr { $$ = Expr\BinaryOp\Mul [$1, $3]; } + | expr '/' expr { $$ = Expr\BinaryOp\Div [$1, $3]; } + | expr '%' expr { $$ = Expr\BinaryOp\Mod [$1, $3]; } + | expr T_SL expr { $$ = Expr\BinaryOp\ShiftLeft [$1, $3]; } + | expr T_SR expr { $$ = Expr\BinaryOp\ShiftRight[$1, $3]; } + | expr T_POW expr { $$ = Expr\BinaryOp\Pow [$1, $3]; } + | '+' expr %prec T_INC { $$ = Expr\UnaryPlus [$2]; } + | '-' expr %prec T_INC { $$ = Expr\UnaryMinus[$2]; } + | '!' expr { $$ = Expr\BooleanNot[$2]; } + | '~' expr { $$ = Expr\BitwiseNot[$2]; } + | expr T_IS_IDENTICAL expr { $$ = Expr\BinaryOp\Identical [$1, $3]; } + | expr T_IS_NOT_IDENTICAL expr { $$ = Expr\BinaryOp\NotIdentical [$1, $3]; } + | expr T_IS_EQUAL expr { $$ = Expr\BinaryOp\Equal [$1, $3]; } + | expr T_IS_NOT_EQUAL expr { $$ = Expr\BinaryOp\NotEqual [$1, $3]; } + | expr T_SPACESHIP expr { $$ = Expr\BinaryOp\Spaceship [$1, $3]; } + | expr '<' expr { $$ = Expr\BinaryOp\Smaller [$1, $3]; } + | expr T_IS_SMALLER_OR_EQUAL expr { $$ = Expr\BinaryOp\SmallerOrEqual[$1, $3]; } + | expr '>' expr { $$ = Expr\BinaryOp\Greater [$1, $3]; } + | expr T_IS_GREATER_OR_EQUAL expr { $$ = Expr\BinaryOp\GreaterOrEqual[$1, $3]; } + | expr T_INSTANCEOF class_name_reference { $$ = Expr\Instanceof_[$1, $3]; } + | parentheses_expr { $$ = $1; } + /* we need a separate '(' new_expr ')' rule to avoid problems caused by a s/r conflict */ + | '(' new_expr ')' { $$ = $2; } + | expr '?' expr ':' expr { $$ = Expr\Ternary[$1, $3, $5]; } + | expr '?' ':' expr { $$ = Expr\Ternary[$1, null, $4]; } + | expr T_COALESCE expr { $$ = Expr\BinaryOp\Coalesce[$1, $3]; } + | T_ISSET '(' variables_list ')' { $$ = Expr\Isset_[$3]; } + | T_EMPTY '(' expr ')' { $$ = Expr\Empty_[$3]; } + | T_INCLUDE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_INCLUDE]; } + | T_INCLUDE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_INCLUDE_ONCE]; } + | T_EVAL parentheses_expr { $$ = Expr\Eval_[$2]; } + | T_REQUIRE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE]; } + | T_REQUIRE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE_ONCE]; } + | T_INT_CAST expr { $$ = Expr\Cast\Int_ [$2]; } + | T_DOUBLE_CAST expr + { $attrs = attributes(); + $attrs['kind'] = $this->getFloatCastKind($1); + $$ = new Expr\Cast\Double($2, $attrs); } + | T_STRING_CAST expr { $$ = Expr\Cast\String_ [$2]; } + | T_ARRAY_CAST expr { $$ = Expr\Cast\Array_ [$2]; } + | T_OBJECT_CAST expr { $$ = Expr\Cast\Object_ [$2]; } + | T_BOOL_CAST expr { $$ = Expr\Cast\Bool_ [$2]; } + | T_UNSET_CAST expr { $$ = Expr\Cast\Unset_ [$2]; } + | T_EXIT exit_expr + { $attrs = attributes(); + $attrs['kind'] = strtolower($1) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE; + $$ = new Expr\Exit_($2, $attrs); } + | '@' expr { $$ = Expr\ErrorSuppress[$2]; } + | scalar { $$ = $1; } + | array_expr { $$ = $1; } + | scalar_dereference { $$ = $1; } + | '`' backticks_expr '`' { $$ = Expr\ShellExec[$2]; } + | T_PRINT expr { $$ = Expr\Print_[$2]; } + | T_YIELD { $$ = Expr\Yield_[null, null]; } + | T_YIELD_FROM expr { $$ = Expr\YieldFrom[$2]; } + | T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type + '{' inner_statement_list '}' + { $$ = Expr\Closure[['static' => false, 'byRef' => $2, 'params' => $4, 'uses' => $6, 'returnType' => $7, 'stmts' => $9]]; } + | T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type + '{' inner_statement_list '}' + { $$ = Expr\Closure[['static' => true, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $10]]; } +; + +parentheses_expr: + '(' expr ')' { $$ = $2; } + | '(' yield_expr ')' { $$ = $2; } +; + +yield_expr: + T_YIELD expr { $$ = Expr\Yield_[$2, null]; } + | T_YIELD expr T_DOUBLE_ARROW expr { $$ = Expr\Yield_[$4, $2]; } +; + +array_expr: + T_ARRAY '(' array_pair_list ')' + { $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_LONG; + $$ = new Expr\Array_($3, $attrs); } + | '[' array_pair_list ']' + { $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_SHORT; + $$ = new Expr\Array_($2, $attrs); } +; + +scalar_dereference: + array_expr '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | T_CONSTANT_ENCAPSED_STRING '[' dim_offset ']' + { $attrs = attributes(); $attrs['kind'] = strKind($1); + $$ = Expr\ArrayDimFetch[new Scalar\String_(Scalar\String_::parse($1), $attrs), $3]; } + | constant '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | scalar_dereference '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + /* alternative array syntax missing intentionally */ +; + +anonymous_class: + T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}' + { $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $3, 'implements' => $4, 'stmts' => $6]], $2); + $this->checkClass($$[0], -1); } +; + +new_expr: + T_NEW class_name_reference ctor_arguments { $$ = Expr\New_[$2, $3]; } + | T_NEW anonymous_class + { list($class, $ctorArgs) = $2; $$ = Expr\New_[$class, $ctorArgs]; } +; + +lexical_vars: + /* empty */ { $$ = array(); } + | T_USE '(' lexical_var_list ')' { $$ = $3; } +; + +lexical_var_list: + lexical_var { init($1); } + | lexical_var_list ',' lexical_var { push($1, $3); } +; + +lexical_var: + optional_ref plain_variable { $$ = Expr\ClosureUse[$2, $1]; } +; + +function_call: + name argument_list { $$ = Expr\FuncCall[$1, $2]; } + | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_ex argument_list + { $$ = Expr\StaticCall[$1, $3, $4]; } + | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '{' expr '}' argument_list + { $$ = Expr\StaticCall[$1, $4, $6]; } + | static_property argument_list + { $$ = $this->fixupPhp5StaticPropCall($1, $2, attributes()); } + | variable_without_objects argument_list + { $$ = Expr\FuncCall[$1, $2]; } + | function_call '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + /* alternative array syntax missing intentionally */ +; + +class_name: + T_STATIC { $$ = Name[$1]; } + | name { $$ = $1; } +; + +name: + T_STRING { $$ = Name[$1]; } + | T_NAME_QUALIFIED { $$ = Name[$1]; } + | T_NAME_FULLY_QUALIFIED { $$ = Name\FullyQualified[substr($1, 1)]; } + | T_NAME_RELATIVE { $$ = Name\Relative[substr($1, 10)]; } +; + +class_name_reference: + class_name { $$ = $1; } + | dynamic_class_name_reference { $$ = $1; } +; + +dynamic_class_name_reference: + object_access_for_dcnr { $$ = $1; } + | base_variable { $$ = $1; } +; + +class_name_or_var: + class_name { $$ = $1; } + | reference_variable { $$ = $1; } +; + +object_access_for_dcnr: + base_variable T_OBJECT_OPERATOR object_property + { $$ = Expr\PropertyFetch[$1, $3]; } + | object_access_for_dcnr T_OBJECT_OPERATOR object_property + { $$ = Expr\PropertyFetch[$1, $3]; } + | object_access_for_dcnr '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | object_access_for_dcnr '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; } +; + +exit_expr: + /* empty */ { $$ = null; } + | '(' ')' { $$ = null; } + | parentheses_expr { $$ = $1; } +; + +backticks_expr: + /* empty */ { $$ = array(); } + | T_ENCAPSED_AND_WHITESPACE + { $$ = array(Scalar\EncapsedStringPart[Scalar\String_::parseEscapeSequences($1, '`', false)]); } + | encaps_list { parseEncapsed($1, '`', false); $$ = $1; } +; + +ctor_arguments: + /* empty */ { $$ = array(); } + | argument_list { $$ = $1; } +; + +common_scalar: + T_LNUMBER { $$ = $this->parseLNumber($1, attributes(), true); } + | T_DNUMBER { $$ = Scalar\DNumber[Scalar\DNumber::parse($1)]; } + | T_CONSTANT_ENCAPSED_STRING + { $attrs = attributes(); $attrs['kind'] = strKind($1); + $$ = new Scalar\String_(Scalar\String_::parse($1, false), $attrs); } + | T_LINE { $$ = Scalar\MagicConst\Line[]; } + | T_FILE { $$ = Scalar\MagicConst\File[]; } + | T_DIR { $$ = Scalar\MagicConst\Dir[]; } + | T_CLASS_C { $$ = Scalar\MagicConst\Class_[]; } + | T_TRAIT_C { $$ = Scalar\MagicConst\Trait_[]; } + | T_METHOD_C { $$ = Scalar\MagicConst\Method[]; } + | T_FUNC_C { $$ = Scalar\MagicConst\Function_[]; } + | T_NS_C { $$ = Scalar\MagicConst\Namespace_[]; } + | T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC + { $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), false); } + | T_START_HEREDOC T_END_HEREDOC + { $$ = $this->parseDocString($1, '', $2, attributes(), stackAttributes(#2), false); } +; + +static_scalar: + common_scalar { $$ = $1; } + | class_name T_PAAMAYIM_NEKUDOTAYIM identifier_ex { $$ = Expr\ClassConstFetch[$1, $3]; } + | name { $$ = Expr\ConstFetch[$1]; } + | T_ARRAY '(' static_array_pair_list ')' { $$ = Expr\Array_[$3]; } + | '[' static_array_pair_list ']' { $$ = Expr\Array_[$2]; } + | static_operation { $$ = $1; } +; + +static_operation: + static_scalar T_BOOLEAN_OR static_scalar { $$ = Expr\BinaryOp\BooleanOr [$1, $3]; } + | static_scalar T_BOOLEAN_AND static_scalar { $$ = Expr\BinaryOp\BooleanAnd[$1, $3]; } + | static_scalar T_LOGICAL_OR static_scalar { $$ = Expr\BinaryOp\LogicalOr [$1, $3]; } + | static_scalar T_LOGICAL_AND static_scalar { $$ = Expr\BinaryOp\LogicalAnd[$1, $3]; } + | static_scalar T_LOGICAL_XOR static_scalar { $$ = Expr\BinaryOp\LogicalXor[$1, $3]; } + | static_scalar '|' static_scalar { $$ = Expr\BinaryOp\BitwiseOr [$1, $3]; } + | static_scalar '&' static_scalar { $$ = Expr\BinaryOp\BitwiseAnd[$1, $3]; } + | static_scalar '^' static_scalar { $$ = Expr\BinaryOp\BitwiseXor[$1, $3]; } + | static_scalar '.' static_scalar { $$ = Expr\BinaryOp\Concat [$1, $3]; } + | static_scalar '+' static_scalar { $$ = Expr\BinaryOp\Plus [$1, $3]; } + | static_scalar '-' static_scalar { $$ = Expr\BinaryOp\Minus [$1, $3]; } + | static_scalar '*' static_scalar { $$ = Expr\BinaryOp\Mul [$1, $3]; } + | static_scalar '/' static_scalar { $$ = Expr\BinaryOp\Div [$1, $3]; } + | static_scalar '%' static_scalar { $$ = Expr\BinaryOp\Mod [$1, $3]; } + | static_scalar T_SL static_scalar { $$ = Expr\BinaryOp\ShiftLeft [$1, $3]; } + | static_scalar T_SR static_scalar { $$ = Expr\BinaryOp\ShiftRight[$1, $3]; } + | static_scalar T_POW static_scalar { $$ = Expr\BinaryOp\Pow [$1, $3]; } + | '+' static_scalar %prec T_INC { $$ = Expr\UnaryPlus [$2]; } + | '-' static_scalar %prec T_INC { $$ = Expr\UnaryMinus[$2]; } + | '!' static_scalar { $$ = Expr\BooleanNot[$2]; } + | '~' static_scalar { $$ = Expr\BitwiseNot[$2]; } + | static_scalar T_IS_IDENTICAL static_scalar { $$ = Expr\BinaryOp\Identical [$1, $3]; } + | static_scalar T_IS_NOT_IDENTICAL static_scalar { $$ = Expr\BinaryOp\NotIdentical [$1, $3]; } + | static_scalar T_IS_EQUAL static_scalar { $$ = Expr\BinaryOp\Equal [$1, $3]; } + | static_scalar T_IS_NOT_EQUAL static_scalar { $$ = Expr\BinaryOp\NotEqual [$1, $3]; } + | static_scalar '<' static_scalar { $$ = Expr\BinaryOp\Smaller [$1, $3]; } + | static_scalar T_IS_SMALLER_OR_EQUAL static_scalar { $$ = Expr\BinaryOp\SmallerOrEqual[$1, $3]; } + | static_scalar '>' static_scalar { $$ = Expr\BinaryOp\Greater [$1, $3]; } + | static_scalar T_IS_GREATER_OR_EQUAL static_scalar { $$ = Expr\BinaryOp\GreaterOrEqual[$1, $3]; } + | static_scalar '?' static_scalar ':' static_scalar { $$ = Expr\Ternary[$1, $3, $5]; } + | static_scalar '?' ':' static_scalar { $$ = Expr\Ternary[$1, null, $4]; } + | static_scalar '[' static_scalar ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | '(' static_scalar ')' { $$ = $2; } +; + +constant: + name { $$ = Expr\ConstFetch[$1]; } + | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_ex + { $$ = Expr\ClassConstFetch[$1, $3]; } +; + +scalar: + common_scalar { $$ = $1; } + | constant { $$ = $1; } + | '"' encaps_list '"' + { $attrs = attributes(); $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED; + parseEncapsed($2, '"', true); $$ = new Scalar\Encapsed($2, $attrs); } + | T_START_HEREDOC encaps_list T_END_HEREDOC + { $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), true); } +; + +static_array_pair_list: + /* empty */ { $$ = array(); } + | non_empty_static_array_pair_list optional_comma { $$ = $1; } +; + +optional_comma: + /* empty */ + | ',' +; + +non_empty_static_array_pair_list: + non_empty_static_array_pair_list ',' static_array_pair { push($1, $3); } + | static_array_pair { init($1); } +; + +static_array_pair: + static_scalar T_DOUBLE_ARROW static_scalar { $$ = Expr\ArrayItem[$3, $1, false]; } + | static_scalar { $$ = Expr\ArrayItem[$1, null, false]; } +; + +variable: + object_access { $$ = $1; } + | base_variable { $$ = $1; } + | function_call { $$ = $1; } + | new_expr_array_deref { $$ = $1; } +; + +new_expr_array_deref: + '(' new_expr ')' '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$2, $5]; } + | new_expr_array_deref '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + /* alternative array syntax missing intentionally */ +; + +object_access: + variable_or_new_expr T_OBJECT_OPERATOR object_property + { $$ = Expr\PropertyFetch[$1, $3]; } + | variable_or_new_expr T_OBJECT_OPERATOR object_property argument_list + { $$ = Expr\MethodCall[$1, $3, $4]; } + | object_access argument_list { $$ = Expr\FuncCall[$1, $2]; } + | object_access '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | object_access '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; } +; + +variable_or_new_expr: + variable { $$ = $1; } + | '(' new_expr ')' { $$ = $2; } +; + +variable_without_objects: + reference_variable { $$ = $1; } + | '$' variable_without_objects { $$ = Expr\Variable[$2]; } +; + +base_variable: + variable_without_objects { $$ = $1; } + | static_property { $$ = $1; } +; + +static_property: + class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '$' reference_variable + { $$ = Expr\StaticPropertyFetch[$1, $4]; } + | static_property_with_arrays { $$ = $1; } +; + +static_property_simple_name: + T_VARIABLE + { $var = parseVar($1); $$ = \is_string($var) ? Node\VarLikeIdentifier[$var] : $var; } +; + +static_property_with_arrays: + class_name_or_var T_PAAMAYIM_NEKUDOTAYIM static_property_simple_name + { $$ = Expr\StaticPropertyFetch[$1, $3]; } + | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM '$' '{' expr '}' + { $$ = Expr\StaticPropertyFetch[$1, $5]; } + | static_property_with_arrays '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | static_property_with_arrays '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; } +; + +reference_variable: + reference_variable '[' dim_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | reference_variable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | plain_variable { $$ = $1; } + | '$' '{' expr '}' { $$ = Expr\Variable[$3]; } +; + +dim_offset: + /* empty */ { $$ = null; } + | expr { $$ = $1; } +; + +object_property: + identifier { $$ = $1; } + | '{' expr '}' { $$ = $2; } + | variable_without_objects { $$ = $1; } + | error { $$ = Expr\Error[]; $this->errorState = 2; } +; + +list_expr: + T_LIST '(' list_expr_elements ')' { $$ = Expr\List_[$3]; } +; + +list_expr_elements: + list_expr_elements ',' list_expr_element { push($1, $3); } + | list_expr_element { init($1); } +; + +list_expr_element: + variable { $$ = Expr\ArrayItem[$1, null, false]; } + | list_expr { $$ = Expr\ArrayItem[$1, null, false]; } + | /* empty */ { $$ = null; } +; + +array_pair_list: + /* empty */ { $$ = array(); } + | non_empty_array_pair_list optional_comma { $$ = $1; } +; + +non_empty_array_pair_list: + non_empty_array_pair_list ',' array_pair { push($1, $3); } + | array_pair { init($1); } +; + +array_pair: + expr T_DOUBLE_ARROW expr { $$ = Expr\ArrayItem[$3, $1, false]; } + | expr { $$ = Expr\ArrayItem[$1, null, false]; } + | expr T_DOUBLE_ARROW '&' variable { $$ = Expr\ArrayItem[$4, $1, true]; } + | '&' variable { $$ = Expr\ArrayItem[$2, null, true]; } + | T_ELLIPSIS expr { $$ = Expr\ArrayItem[$2, null, false, attributes(), true]; } +; + +encaps_list: + encaps_list encaps_var { push($1, $2); } + | encaps_list encaps_string_part { push($1, $2); } + | encaps_var { init($1); } + | encaps_string_part encaps_var { init($1, $2); } +; + +encaps_string_part: + T_ENCAPSED_AND_WHITESPACE { $$ = Scalar\EncapsedStringPart[$1]; } +; + +encaps_str_varname: + T_STRING_VARNAME { $$ = Expr\Variable[$1]; } +; + +encaps_var: + plain_variable { $$ = $1; } + | plain_variable '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | plain_variable T_OBJECT_OPERATOR identifier { $$ = Expr\PropertyFetch[$1, $3]; } + | T_DOLLAR_OPEN_CURLY_BRACES expr '}' { $$ = Expr\Variable[$2]; } + | T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '}' { $$ = Expr\Variable[$2]; } + | T_DOLLAR_OPEN_CURLY_BRACES encaps_str_varname '[' expr ']' '}' + { $$ = Expr\ArrayDimFetch[$2, $4]; } + | T_CURLY_OPEN variable '}' { $$ = $2; } +; + +encaps_var_offset: + T_STRING { $$ = Scalar\String_[$1]; } + | T_NUM_STRING { $$ = $this->parseNumString($1, attributes()); } + | plain_variable { $$ = $1; } +; + +%% diff --git a/vendor-bundle/phabel/php-parser/grammar/php7.y b/vendor-bundle/phabel/php-parser/grammar/php7.y new file mode 100644 index 000000000..4ca244d8a --- /dev/null +++ b/vendor-bundle/phabel/php-parser/grammar/php7.y @@ -0,0 +1,1138 @@ +%pure_parser +%expect 2 + +%tokens + +%% + +start: + top_statement_list { $$ = $this->handleNamespaces($1); } +; + +top_statement_list_ex: + top_statement_list_ex top_statement { pushNormalizing($1, $2); } + | /* empty */ { init(); } +; + +top_statement_list: + top_statement_list_ex + { makeZeroLengthNop($nop, $this->lookaheadStartAttributes); + if ($nop !== null) { $1[] = $nop; } $$ = $1; } +; + +reserved_non_modifiers: + T_INCLUDE | T_INCLUDE_ONCE | T_EVAL | T_REQUIRE | T_REQUIRE_ONCE | T_LOGICAL_OR | T_LOGICAL_XOR | T_LOGICAL_AND + | T_INSTANCEOF | T_NEW | T_CLONE | T_EXIT | T_IF | T_ELSEIF | T_ELSE | T_ENDIF | T_ECHO | T_DO | T_WHILE + | T_ENDWHILE | T_FOR | T_ENDFOR | T_FOREACH | T_ENDFOREACH | T_DECLARE | T_ENDDECLARE | T_AS | T_TRY | T_CATCH + | T_FINALLY | T_THROW | T_USE | T_INSTEADOF | T_GLOBAL | T_VAR | T_UNSET | T_ISSET | T_EMPTY | T_CONTINUE | T_GOTO + | T_FUNCTION | T_CONST | T_RETURN | T_PRINT | T_YIELD | T_LIST | T_SWITCH | T_ENDSWITCH | T_CASE | T_DEFAULT + | T_BREAK | T_ARRAY | T_CALLABLE | T_EXTENDS | T_IMPLEMENTS | T_NAMESPACE | T_TRAIT | T_INTERFACE | T_CLASS + | T_CLASS_C | T_TRAIT_C | T_FUNC_C | T_METHOD_C | T_LINE | T_FILE | T_DIR | T_NS_C | T_HALT_COMPILER | T_FN + | T_MATCH +; + +semi_reserved: + reserved_non_modifiers + | T_STATIC | T_ABSTRACT | T_FINAL | T_PRIVATE | T_PROTECTED | T_PUBLIC +; + +identifier_ex: + T_STRING { $$ = Node\Identifier[$1]; } + | semi_reserved { $$ = Node\Identifier[$1]; } +; + +identifier: + T_STRING { $$ = Node\Identifier[$1]; } +; + +reserved_non_modifiers_identifier: + reserved_non_modifiers { $$ = Node\Identifier[$1]; } +; + +namespace_declaration_name: + T_STRING { $$ = Name[$1]; } + | semi_reserved { $$ = Name[$1]; } + | T_NAME_QUALIFIED { $$ = Name[$1]; } +; + +namespace_name: + T_STRING { $$ = Name[$1]; } + | T_NAME_QUALIFIED { $$ = Name[$1]; } +; + +legacy_namespace_name: + namespace_name { $$ = $1; } + | T_NAME_FULLY_QUALIFIED { $$ = Name[substr($1, 1)]; } +; + +plain_variable: + T_VARIABLE { $$ = Expr\Variable[parseVar($1)]; } +; + +semi: + ';' { /* nothing */ } + | error { /* nothing */ } +; + +no_comma: + /* empty */ { /* nothing */ } + | ',' { $this->emitError(new Error('A trailing comma is not allowed here', attributes())); } +; + +optional_comma: + /* empty */ + | ',' +; + +attribute_decl: + class_name { $$ = Node\Attribute[$1, []]; } + | class_name argument_list { $$ = Node\Attribute[$1, $2]; } +; + +attribute_group: + attribute_decl { init($1); } + | attribute_group ',' attribute_decl { push($1, $3); } +; + +attribute: + T_ATTRIBUTE attribute_group optional_comma ']' { $$ = Node\AttributeGroup[$2]; } +; + +attributes: + attribute { init($1); } + | attributes attribute { push($1, $2); } +; + +optional_attributes: + /* empty */ { $$ = []; } + | attributes { $$ = $1; } +; + +top_statement: + statement { $$ = $1; } + | function_declaration_statement { $$ = $1; } + | class_declaration_statement { $$ = $1; } + | T_HALT_COMPILER + { $$ = Stmt\HaltCompiler[$this->lexer->handleHaltCompiler()]; } + | T_NAMESPACE namespace_declaration_name semi + { $$ = Stmt\Namespace_[$2, null]; + $$->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON); + $this->checkNamespace($$); } + | T_NAMESPACE namespace_declaration_name '{' top_statement_list '}' + { $$ = Stmt\Namespace_[$2, $4]; + $$->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $this->checkNamespace($$); } + | T_NAMESPACE '{' top_statement_list '}' + { $$ = Stmt\Namespace_[null, $3]; + $$->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $this->checkNamespace($$); } + | T_USE use_declarations semi { $$ = Stmt\Use_[$2, Stmt\Use_::TYPE_NORMAL]; } + | T_USE use_type use_declarations semi { $$ = Stmt\Use_[$3, $2]; } + | group_use_declaration semi { $$ = $1; } + | T_CONST constant_declaration_list semi { $$ = Stmt\Const_[$2]; } +; + +use_type: + T_FUNCTION { $$ = Stmt\Use_::TYPE_FUNCTION; } + | T_CONST { $$ = Stmt\Use_::TYPE_CONSTANT; } +; + +group_use_declaration: + T_USE use_type legacy_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}' + { $$ = Stmt\GroupUse[$3, $6, $2]; } + | T_USE legacy_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}' + { $$ = Stmt\GroupUse[$2, $5, Stmt\Use_::TYPE_UNKNOWN]; } +; + +unprefixed_use_declarations: + non_empty_unprefixed_use_declarations optional_comma { $$ = $1; } +; + +non_empty_unprefixed_use_declarations: + non_empty_unprefixed_use_declarations ',' unprefixed_use_declaration + { push($1, $3); } + | unprefixed_use_declaration { init($1); } +; + +use_declarations: + non_empty_use_declarations no_comma { $$ = $1; } +; + +non_empty_use_declarations: + non_empty_use_declarations ',' use_declaration { push($1, $3); } + | use_declaration { init($1); } +; + +inline_use_declarations: + non_empty_inline_use_declarations optional_comma { $$ = $1; } +; + +non_empty_inline_use_declarations: + non_empty_inline_use_declarations ',' inline_use_declaration + { push($1, $3); } + | inline_use_declaration { init($1); } +; + +unprefixed_use_declaration: + namespace_name + { $$ = Stmt\UseUse[$1, null, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #1); } + | namespace_name T_AS identifier + { $$ = Stmt\UseUse[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #3); } +; + +use_declaration: + legacy_namespace_name + { $$ = Stmt\UseUse[$1, null, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #1); } + | legacy_namespace_name T_AS identifier + { $$ = Stmt\UseUse[$1, $3, Stmt\Use_::TYPE_UNKNOWN]; $this->checkUseUse($$, #3); } +; + +inline_use_declaration: + unprefixed_use_declaration { $$ = $1; $$->type = Stmt\Use_::TYPE_NORMAL; } + | use_type unprefixed_use_declaration { $$ = $2; $$->type = $1; } +; + +constant_declaration_list: + non_empty_constant_declaration_list no_comma { $$ = $1; } +; + +non_empty_constant_declaration_list: + non_empty_constant_declaration_list ',' constant_declaration + { push($1, $3); } + | constant_declaration { init($1); } +; + +constant_declaration: + identifier '=' expr { $$ = Node\Const_[$1, $3]; } +; + +class_const_list: + non_empty_class_const_list no_comma { $$ = $1; } +; + +non_empty_class_const_list: + non_empty_class_const_list ',' class_const { push($1, $3); } + | class_const { init($1); } +; + +class_const: + identifier_ex '=' expr { $$ = Node\Const_[$1, $3]; } +; + +inner_statement_list_ex: + inner_statement_list_ex inner_statement { pushNormalizing($1, $2); } + | /* empty */ { init(); } +; + +inner_statement_list: + inner_statement_list_ex + { makeZeroLengthNop($nop, $this->lookaheadStartAttributes); + if ($nop !== null) { $1[] = $nop; } $$ = $1; } +; + +inner_statement: + statement { $$ = $1; } + | function_declaration_statement { $$ = $1; } + | class_declaration_statement { $$ = $1; } + | T_HALT_COMPILER + { throw new Error('__HALT_COMPILER() can only be used from the outermost scope', attributes()); } +; + +non_empty_statement: + '{' inner_statement_list '}' + { + if ($2) { + $$ = $2; prependLeadingComments($$); + } else { + makeNop($$, $this->startAttributeStack[#1], $this->endAttributes); + if (null === $$) { $$ = array(); } + } + } + | T_IF '(' expr ')' statement elseif_list else_single + { $$ = Stmt\If_[$3, ['stmts' => toArray($5), 'elseifs' => $6, 'else' => $7]]; } + | T_IF '(' expr ')' ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';' + { $$ = Stmt\If_[$3, ['stmts' => $6, 'elseifs' => $7, 'else' => $8]]; } + | T_WHILE '(' expr ')' while_statement { $$ = Stmt\While_[$3, $5]; } + | T_DO statement T_WHILE '(' expr ')' ';' { $$ = Stmt\Do_ [$5, toArray($2)]; } + | T_FOR '(' for_expr ';' for_expr ';' for_expr ')' for_statement + { $$ = Stmt\For_[['init' => $3, 'cond' => $5, 'loop' => $7, 'stmts' => $9]]; } + | T_SWITCH '(' expr ')' switch_case_list { $$ = Stmt\Switch_[$3, $5]; } + | T_BREAK optional_expr semi { $$ = Stmt\Break_[$2]; } + | T_CONTINUE optional_expr semi { $$ = Stmt\Continue_[$2]; } + | T_RETURN optional_expr semi { $$ = Stmt\Return_[$2]; } + | T_GLOBAL global_var_list semi { $$ = Stmt\Global_[$2]; } + | T_STATIC static_var_list semi { $$ = Stmt\Static_[$2]; } + | T_ECHO expr_list_forbid_comma semi { $$ = Stmt\Echo_[$2]; } + | T_INLINE_HTML { $$ = Stmt\InlineHTML[$1]; } + | expr semi { + $e = $1; + if ($e instanceof Expr\Throw_) { + // For backwards-compatibility reasons, convert throw in statement position into + // Stmt\Throw_ rather than Stmt\Expression(Expr\Throw_). + $$ = Stmt\Throw_[$e->expr]; + } else { + $$ = Stmt\Expression[$e]; + } + } + | T_UNSET '(' variables_list ')' semi { $$ = Stmt\Unset_[$3]; } + | T_FOREACH '(' expr T_AS foreach_variable ')' foreach_statement + { $$ = Stmt\Foreach_[$3, $5[0], ['keyVar' => null, 'byRef' => $5[1], 'stmts' => $7]]; } + | T_FOREACH '(' expr T_AS variable T_DOUBLE_ARROW foreach_variable ')' foreach_statement + { $$ = Stmt\Foreach_[$3, $7[0], ['keyVar' => $5, 'byRef' => $7[1], 'stmts' => $9]]; } + | T_FOREACH '(' expr error ')' foreach_statement + { $$ = Stmt\Foreach_[$3, new Expr\Error(stackAttributes(#4)), ['stmts' => $6]]; } + | T_DECLARE '(' declare_list ')' declare_statement { $$ = Stmt\Declare_[$3, $5]; } + | T_TRY '{' inner_statement_list '}' catches optional_finally + { $$ = Stmt\TryCatch[$3, $5, $6]; $this->checkTryCatch($$); } + | T_GOTO identifier semi { $$ = Stmt\Goto_[$2]; } + | identifier ':' { $$ = Stmt\Label[$1]; } + | error { $$ = array(); /* means: no statement */ } +; + +statement: + non_empty_statement { $$ = $1; } + | ';' + { makeNop($$, $this->startAttributeStack[#1], $this->endAttributes); + if ($$ === null) $$ = array(); /* means: no statement */ } +; + +catches: + /* empty */ { init(); } + | catches catch { push($1, $2); } +; + +name_union: + name { init($1); } + | name_union '|' name { push($1, $3); } +; + +catch: + T_CATCH '(' name_union optional_plain_variable ')' '{' inner_statement_list '}' + { $$ = Stmt\Catch_[$3, $4, $7]; } +; + +optional_finally: + /* empty */ { $$ = null; } + | T_FINALLY '{' inner_statement_list '}' { $$ = Stmt\Finally_[$3]; } +; + +variables_list: + non_empty_variables_list optional_comma { $$ = $1; } +; + +non_empty_variables_list: + variable { init($1); } + | non_empty_variables_list ',' variable { push($1, $3); } +; + +optional_ref: + /* empty */ { $$ = false; } + | '&' { $$ = true; } +; + +optional_ellipsis: + /* empty */ { $$ = false; } + | T_ELLIPSIS { $$ = true; } +; + +block_or_error: + '{' inner_statement_list '}' { $$ = $2; } + | error { $$ = []; } +; + +function_declaration_statement: + T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type block_or_error + { $$ = Stmt\Function_[$3, ['byRef' => $2, 'params' => $5, 'returnType' => $7, 'stmts' => $8, 'attrGroups' => []]]; } + | attributes T_FUNCTION optional_ref identifier '(' parameter_list ')' optional_return_type block_or_error + { $$ = Stmt\Function_[$4, ['byRef' => $3, 'params' => $6, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => $1]]; } +; + +class_declaration_statement: + optional_attributes class_entry_type identifier extends_from implements_list '{' class_statement_list '}' + { $$ = Stmt\Class_[$3, ['type' => $2, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]]; + $this->checkClass($$, #3); } + | optional_attributes T_INTERFACE identifier interface_extends_list '{' class_statement_list '}' + { $$ = Stmt\Interface_[$3, ['extends' => $4, 'stmts' => $6, 'attrGroups' => $1]]; + $this->checkInterface($$, #3); } + | optional_attributes T_TRAIT identifier '{' class_statement_list '}' + { $$ = Stmt\Trait_[$3, ['stmts' => $5, 'attrGroups' => $1]]; } +; + +class_entry_type: + T_CLASS { $$ = 0; } + | T_ABSTRACT T_CLASS { $$ = Stmt\Class_::MODIFIER_ABSTRACT; } + | T_FINAL T_CLASS { $$ = Stmt\Class_::MODIFIER_FINAL; } +; + +extends_from: + /* empty */ { $$ = null; } + | T_EXTENDS class_name { $$ = $2; } +; + +interface_extends_list: + /* empty */ { $$ = array(); } + | T_EXTENDS class_name_list { $$ = $2; } +; + +implements_list: + /* empty */ { $$ = array(); } + | T_IMPLEMENTS class_name_list { $$ = $2; } +; + +class_name_list: + non_empty_class_name_list no_comma { $$ = $1; } +; + +non_empty_class_name_list: + class_name { init($1); } + | non_empty_class_name_list ',' class_name { push($1, $3); } +; + +for_statement: + statement { $$ = toArray($1); } + | ':' inner_statement_list T_ENDFOR ';' { $$ = $2; } +; + +foreach_statement: + statement { $$ = toArray($1); } + | ':' inner_statement_list T_ENDFOREACH ';' { $$ = $2; } +; + +declare_statement: + non_empty_statement { $$ = toArray($1); } + | ';' { $$ = null; } + | ':' inner_statement_list T_ENDDECLARE ';' { $$ = $2; } +; + +declare_list: + non_empty_declare_list no_comma { $$ = $1; } +; + +non_empty_declare_list: + declare_list_element { init($1); } + | non_empty_declare_list ',' declare_list_element { push($1, $3); } +; + +declare_list_element: + identifier '=' expr { $$ = Stmt\DeclareDeclare[$1, $3]; } +; + +switch_case_list: + '{' case_list '}' { $$ = $2; } + | '{' ';' case_list '}' { $$ = $3; } + | ':' case_list T_ENDSWITCH ';' { $$ = $2; } + | ':' ';' case_list T_ENDSWITCH ';' { $$ = $3; } +; + +case_list: + /* empty */ { init(); } + | case_list case { push($1, $2); } +; + +case: + T_CASE expr case_separator inner_statement_list_ex { $$ = Stmt\Case_[$2, $4]; } + | T_DEFAULT case_separator inner_statement_list_ex { $$ = Stmt\Case_[null, $3]; } +; + +case_separator: + ':' + | ';' +; + +match: + T_MATCH '(' expr ')' '{' match_arm_list '}' { $$ = Expr\Match_[$3, $6]; } +; + +match_arm_list: + /* empty */ { $$ = []; } + | non_empty_match_arm_list optional_comma { $$ = $1; } +; + +non_empty_match_arm_list: + match_arm { init($1); } + | non_empty_match_arm_list ',' match_arm { push($1, $3); } +; + +match_arm: + expr_list_allow_comma T_DOUBLE_ARROW expr { $$ = Node\MatchArm[$1, $3]; } + | T_DEFAULT optional_comma T_DOUBLE_ARROW expr { $$ = Node\MatchArm[null, $4]; } +; + +while_statement: + statement { $$ = toArray($1); } + | ':' inner_statement_list T_ENDWHILE ';' { $$ = $2; } +; + +elseif_list: + /* empty */ { init(); } + | elseif_list elseif { push($1, $2); } +; + +elseif: + T_ELSEIF '(' expr ')' statement { $$ = Stmt\ElseIf_[$3, toArray($5)]; } +; + +new_elseif_list: + /* empty */ { init(); } + | new_elseif_list new_elseif { push($1, $2); } +; + +new_elseif: + T_ELSEIF '(' expr ')' ':' inner_statement_list { $$ = Stmt\ElseIf_[$3, $6]; } +; + +else_single: + /* empty */ { $$ = null; } + | T_ELSE statement { $$ = Stmt\Else_[toArray($2)]; } +; + +new_else_single: + /* empty */ { $$ = null; } + | T_ELSE ':' inner_statement_list { $$ = Stmt\Else_[$3]; } +; + +foreach_variable: + variable { $$ = array($1, false); } + | '&' variable { $$ = array($2, true); } + | list_expr { $$ = array($1, false); } + | array_short_syntax { $$ = array($1, false); } +; + +parameter_list: + non_empty_parameter_list optional_comma { $$ = $1; } + | /* empty */ { $$ = array(); } +; + +non_empty_parameter_list: + parameter { init($1); } + | non_empty_parameter_list ',' parameter { push($1, $3); } +; + +optional_visibility_modifier: + /* empty */ { $$ = 0; } + | T_PUBLIC { $$ = Stmt\Class_::MODIFIER_PUBLIC; } + | T_PROTECTED { $$ = Stmt\Class_::MODIFIER_PROTECTED; } + | T_PRIVATE { $$ = Stmt\Class_::MODIFIER_PRIVATE; } +; + +parameter: + optional_attributes optional_visibility_modifier optional_type_without_static optional_ref optional_ellipsis plain_variable + { $$ = new Node\Param($6, null, $3, $4, $5, attributes(), $2, $1); + $this->checkParam($$); } + | optional_attributes optional_visibility_modifier optional_type_without_static optional_ref optional_ellipsis plain_variable '=' expr + { $$ = new Node\Param($6, $8, $3, $4, $5, attributes(), $2, $1); + $this->checkParam($$); } + | optional_attributes optional_visibility_modifier optional_type_without_static optional_ref optional_ellipsis error + { $$ = new Node\Param(Expr\Error[], null, $3, $4, $5, attributes(), $2, $1); } +; + +type_expr: + type { $$ = $1; } + | '?' type { $$ = Node\NullableType[$2]; } + | union_type { $$ = Node\UnionType[$1]; } +; + +type: + type_without_static { $$ = $1; } + | T_STATIC { $$ = Node\Name['static']; } +; + +type_without_static: + name { $$ = $this->handleBuiltinTypes($1); } + | T_ARRAY { $$ = Node\Identifier['array']; } + | T_CALLABLE { $$ = Node\Identifier['callable']; } +; + +union_type: + type '|' type { init($1, $3); } + | union_type '|' type { push($1, $3); } +; + +union_type_without_static: + type_without_static '|' type_without_static { init($1, $3); } + | union_type_without_static '|' type_without_static { push($1, $3); } +; + +type_expr_without_static: + type_without_static { $$ = $1; } + | '?' type_without_static { $$ = Node\NullableType[$2]; } + | union_type_without_static { $$ = Node\UnionType[$1]; } +; + +optional_type_without_static: + /* empty */ { $$ = null; } + | type_expr_without_static { $$ = $1; } +; + +optional_return_type: + /* empty */ { $$ = null; } + | ':' type_expr { $$ = $2; } + | ':' error { $$ = null; } +; + +argument_list: + '(' ')' { $$ = array(); } + | '(' non_empty_argument_list optional_comma ')' { $$ = $2; } +; + +non_empty_argument_list: + argument { init($1); } + | non_empty_argument_list ',' argument { push($1, $3); } +; + +argument: + expr { $$ = Node\Arg[$1, false, false]; } + | '&' variable { $$ = Node\Arg[$2, true, false]; } + | T_ELLIPSIS expr { $$ = Node\Arg[$2, false, true]; } + | identifier_ex ':' expr + { $$ = new Node\Arg($3, false, false, attributes(), $1); } +; + +global_var_list: + non_empty_global_var_list no_comma { $$ = $1; } +; + +non_empty_global_var_list: + non_empty_global_var_list ',' global_var { push($1, $3); } + | global_var { init($1); } +; + +global_var: + simple_variable { $$ = $1; } +; + +static_var_list: + non_empty_static_var_list no_comma { $$ = $1; } +; + +non_empty_static_var_list: + non_empty_static_var_list ',' static_var { push($1, $3); } + | static_var { init($1); } +; + +static_var: + plain_variable { $$ = Stmt\StaticVar[$1, null]; } + | plain_variable '=' expr { $$ = Stmt\StaticVar[$1, $3]; } +; + +class_statement_list_ex: + class_statement_list_ex class_statement { if ($2 !== null) { push($1, $2); } } + | /* empty */ { init(); } +; + +class_statement_list: + class_statement_list_ex + { makeZeroLengthNop($nop, $this->lookaheadStartAttributes); + if ($nop !== null) { $1[] = $nop; } $$ = $1; } +; + +class_statement: + optional_attributes variable_modifiers optional_type_without_static property_declaration_list semi + { $$ = new Stmt\Property($2, $4, attributes(), $3, $1); + $this->checkProperty($$, #2); } + | optional_attributes method_modifiers T_CONST class_const_list semi + { $$ = new Stmt\ClassConst($4, $2, attributes(), $1); + $this->checkClassConst($$, #2); } + | optional_attributes method_modifiers T_FUNCTION optional_ref identifier_ex '(' parameter_list ')' optional_return_type method_body + { $$ = Stmt\ClassMethod[$5, ['type' => $2, 'byRef' => $4, 'params' => $7, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]]; + $this->checkClassMethod($$, #2); } + | T_USE class_name_list trait_adaptations { $$ = Stmt\TraitUse[$2, $3]; } + | error { $$ = null; /* will be skipped */ } +; + +trait_adaptations: + ';' { $$ = array(); } + | '{' trait_adaptation_list '}' { $$ = $2; } +; + +trait_adaptation_list: + /* empty */ { init(); } + | trait_adaptation_list trait_adaptation { push($1, $2); } +; + +trait_adaptation: + trait_method_reference_fully_qualified T_INSTEADOF class_name_list ';' + { $$ = Stmt\TraitUseAdaptation\Precedence[$1[0], $1[1], $3]; } + | trait_method_reference T_AS member_modifier identifier_ex ';' + { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, $4]; } + | trait_method_reference T_AS member_modifier ';' + { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], $3, null]; } + | trait_method_reference T_AS identifier ';' + { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; } + | trait_method_reference T_AS reserved_non_modifiers_identifier ';' + { $$ = Stmt\TraitUseAdaptation\Alias[$1[0], $1[1], null, $3]; } +; + +trait_method_reference_fully_qualified: + name T_PAAMAYIM_NEKUDOTAYIM identifier_ex { $$ = array($1, $3); } +; +trait_method_reference: + trait_method_reference_fully_qualified { $$ = $1; } + | identifier_ex { $$ = array(null, $1); } +; + +method_body: + ';' /* abstract method */ { $$ = null; } + | block_or_error { $$ = $1; } +; + +variable_modifiers: + non_empty_member_modifiers { $$ = $1; } + | T_VAR { $$ = 0; } +; + +method_modifiers: + /* empty */ { $$ = 0; } + | non_empty_member_modifiers { $$ = $1; } +; + +non_empty_member_modifiers: + member_modifier { $$ = $1; } + | non_empty_member_modifiers member_modifier { $this->checkModifier($1, $2, #2); $$ = $1 | $2; } +; + +member_modifier: + T_PUBLIC { $$ = Stmt\Class_::MODIFIER_PUBLIC; } + | T_PROTECTED { $$ = Stmt\Class_::MODIFIER_PROTECTED; } + | T_PRIVATE { $$ = Stmt\Class_::MODIFIER_PRIVATE; } + | T_STATIC { $$ = Stmt\Class_::MODIFIER_STATIC; } + | T_ABSTRACT { $$ = Stmt\Class_::MODIFIER_ABSTRACT; } + | T_FINAL { $$ = Stmt\Class_::MODIFIER_FINAL; } +; + +property_declaration_list: + non_empty_property_declaration_list no_comma { $$ = $1; } +; + +non_empty_property_declaration_list: + property_declaration { init($1); } + | non_empty_property_declaration_list ',' property_declaration + { push($1, $3); } +; + +property_decl_name: + T_VARIABLE { $$ = Node\VarLikeIdentifier[parseVar($1)]; } +; + +property_declaration: + property_decl_name { $$ = Stmt\PropertyProperty[$1, null]; } + | property_decl_name '=' expr { $$ = Stmt\PropertyProperty[$1, $3]; } +; + +expr_list_forbid_comma: + non_empty_expr_list no_comma { $$ = $1; } +; + +expr_list_allow_comma: + non_empty_expr_list optional_comma { $$ = $1; } +; + +non_empty_expr_list: + non_empty_expr_list ',' expr { push($1, $3); } + | expr { init($1); } +; + +for_expr: + /* empty */ { $$ = array(); } + | expr_list_forbid_comma { $$ = $1; } +; + +expr: + variable { $$ = $1; } + | list_expr '=' expr { $$ = Expr\Assign[$1, $3]; } + | array_short_syntax '=' expr { $$ = Expr\Assign[$1, $3]; } + | variable '=' expr { $$ = Expr\Assign[$1, $3]; } + | variable '=' '&' variable { $$ = Expr\AssignRef[$1, $4]; } + | new_expr { $$ = $1; } + | match { $$ = $1; } + | T_CLONE expr { $$ = Expr\Clone_[$2]; } + | variable T_PLUS_EQUAL expr { $$ = Expr\AssignOp\Plus [$1, $3]; } + | variable T_MINUS_EQUAL expr { $$ = Expr\AssignOp\Minus [$1, $3]; } + | variable T_MUL_EQUAL expr { $$ = Expr\AssignOp\Mul [$1, $3]; } + | variable T_DIV_EQUAL expr { $$ = Expr\AssignOp\Div [$1, $3]; } + | variable T_CONCAT_EQUAL expr { $$ = Expr\AssignOp\Concat [$1, $3]; } + | variable T_MOD_EQUAL expr { $$ = Expr\AssignOp\Mod [$1, $3]; } + | variable T_AND_EQUAL expr { $$ = Expr\AssignOp\BitwiseAnd[$1, $3]; } + | variable T_OR_EQUAL expr { $$ = Expr\AssignOp\BitwiseOr [$1, $3]; } + | variable T_XOR_EQUAL expr { $$ = Expr\AssignOp\BitwiseXor[$1, $3]; } + | variable T_SL_EQUAL expr { $$ = Expr\AssignOp\ShiftLeft [$1, $3]; } + | variable T_SR_EQUAL expr { $$ = Expr\AssignOp\ShiftRight[$1, $3]; } + | variable T_POW_EQUAL expr { $$ = Expr\AssignOp\Pow [$1, $3]; } + | variable T_COALESCE_EQUAL expr { $$ = Expr\AssignOp\Coalesce [$1, $3]; } + | variable T_INC { $$ = Expr\PostInc[$1]; } + | T_INC variable { $$ = Expr\PreInc [$2]; } + | variable T_DEC { $$ = Expr\PostDec[$1]; } + | T_DEC variable { $$ = Expr\PreDec [$2]; } + | expr T_BOOLEAN_OR expr { $$ = Expr\BinaryOp\BooleanOr [$1, $3]; } + | expr T_BOOLEAN_AND expr { $$ = Expr\BinaryOp\BooleanAnd[$1, $3]; } + | expr T_LOGICAL_OR expr { $$ = Expr\BinaryOp\LogicalOr [$1, $3]; } + | expr T_LOGICAL_AND expr { $$ = Expr\BinaryOp\LogicalAnd[$1, $3]; } + | expr T_LOGICAL_XOR expr { $$ = Expr\BinaryOp\LogicalXor[$1, $3]; } + | expr '|' expr { $$ = Expr\BinaryOp\BitwiseOr [$1, $3]; } + | expr '&' expr { $$ = Expr\BinaryOp\BitwiseAnd[$1, $3]; } + | expr '^' expr { $$ = Expr\BinaryOp\BitwiseXor[$1, $3]; } + | expr '.' expr { $$ = Expr\BinaryOp\Concat [$1, $3]; } + | expr '+' expr { $$ = Expr\BinaryOp\Plus [$1, $3]; } + | expr '-' expr { $$ = Expr\BinaryOp\Minus [$1, $3]; } + | expr '*' expr { $$ = Expr\BinaryOp\Mul [$1, $3]; } + | expr '/' expr { $$ = Expr\BinaryOp\Div [$1, $3]; } + | expr '%' expr { $$ = Expr\BinaryOp\Mod [$1, $3]; } + | expr T_SL expr { $$ = Expr\BinaryOp\ShiftLeft [$1, $3]; } + | expr T_SR expr { $$ = Expr\BinaryOp\ShiftRight[$1, $3]; } + | expr T_POW expr { $$ = Expr\BinaryOp\Pow [$1, $3]; } + | '+' expr %prec T_INC { $$ = Expr\UnaryPlus [$2]; } + | '-' expr %prec T_INC { $$ = Expr\UnaryMinus[$2]; } + | '!' expr { $$ = Expr\BooleanNot[$2]; } + | '~' expr { $$ = Expr\BitwiseNot[$2]; } + | expr T_IS_IDENTICAL expr { $$ = Expr\BinaryOp\Identical [$1, $3]; } + | expr T_IS_NOT_IDENTICAL expr { $$ = Expr\BinaryOp\NotIdentical [$1, $3]; } + | expr T_IS_EQUAL expr { $$ = Expr\BinaryOp\Equal [$1, $3]; } + | expr T_IS_NOT_EQUAL expr { $$ = Expr\BinaryOp\NotEqual [$1, $3]; } + | expr T_SPACESHIP expr { $$ = Expr\BinaryOp\Spaceship [$1, $3]; } + | expr '<' expr { $$ = Expr\BinaryOp\Smaller [$1, $3]; } + | expr T_IS_SMALLER_OR_EQUAL expr { $$ = Expr\BinaryOp\SmallerOrEqual[$1, $3]; } + | expr '>' expr { $$ = Expr\BinaryOp\Greater [$1, $3]; } + | expr T_IS_GREATER_OR_EQUAL expr { $$ = Expr\BinaryOp\GreaterOrEqual[$1, $3]; } + | expr T_INSTANCEOF class_name_reference { $$ = Expr\Instanceof_[$1, $3]; } + | '(' expr ')' { $$ = $2; } + | expr '?' expr ':' expr { $$ = Expr\Ternary[$1, $3, $5]; } + | expr '?' ':' expr { $$ = Expr\Ternary[$1, null, $4]; } + | expr T_COALESCE expr { $$ = Expr\BinaryOp\Coalesce[$1, $3]; } + | T_ISSET '(' expr_list_allow_comma ')' { $$ = Expr\Isset_[$3]; } + | T_EMPTY '(' expr ')' { $$ = Expr\Empty_[$3]; } + | T_INCLUDE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_INCLUDE]; } + | T_INCLUDE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_INCLUDE_ONCE]; } + | T_EVAL '(' expr ')' { $$ = Expr\Eval_[$3]; } + | T_REQUIRE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE]; } + | T_REQUIRE_ONCE expr { $$ = Expr\Include_[$2, Expr\Include_::TYPE_REQUIRE_ONCE]; } + | T_INT_CAST expr { $$ = Expr\Cast\Int_ [$2]; } + | T_DOUBLE_CAST expr + { $attrs = attributes(); + $attrs['kind'] = $this->getFloatCastKind($1); + $$ = new Expr\Cast\Double($2, $attrs); } + | T_STRING_CAST expr { $$ = Expr\Cast\String_ [$2]; } + | T_ARRAY_CAST expr { $$ = Expr\Cast\Array_ [$2]; } + | T_OBJECT_CAST expr { $$ = Expr\Cast\Object_ [$2]; } + | T_BOOL_CAST expr { $$ = Expr\Cast\Bool_ [$2]; } + | T_UNSET_CAST expr { $$ = Expr\Cast\Unset_ [$2]; } + | T_EXIT exit_expr + { $attrs = attributes(); + $attrs['kind'] = strtolower($1) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE; + $$ = new Expr\Exit_($2, $attrs); } + | '@' expr { $$ = Expr\ErrorSuppress[$2]; } + | scalar { $$ = $1; } + | '`' backticks_expr '`' { $$ = Expr\ShellExec[$2]; } + | T_PRINT expr { $$ = Expr\Print_[$2]; } + | T_YIELD { $$ = Expr\Yield_[null, null]; } + | T_YIELD expr { $$ = Expr\Yield_[$2, null]; } + | T_YIELD expr T_DOUBLE_ARROW expr { $$ = Expr\Yield_[$4, $2]; } + | T_YIELD_FROM expr { $$ = Expr\YieldFrom[$2]; } + | T_THROW expr { $$ = Expr\Throw_[$2]; } + + | T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr + { $$ = Expr\ArrowFunction[['static' => false, 'byRef' => $2, 'params' => $4, 'returnType' => $6, 'expr' => $8, 'attrGroups' => []]]; } + | T_STATIC T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr + { $$ = Expr\ArrowFunction[['static' => true, 'byRef' => $3, 'params' => $5, 'returnType' => $7, 'expr' => $9, 'attrGroups' => []]]; } + | T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error + { $$ = Expr\Closure[['static' => false, 'byRef' => $2, 'params' => $4, 'uses' => $6, 'returnType' => $7, 'stmts' => $8, 'attrGroups' => []]]; } + | T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error + { $$ = Expr\Closure[['static' => true, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => []]]; } + + | attributes T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr + { $$ = Expr\ArrowFunction[['static' => false, 'byRef' => $3, 'params' => $5, 'returnType' => $7, 'expr' => $9, 'attrGroups' => $1]]; } + | attributes T_STATIC T_FN optional_ref '(' parameter_list ')' optional_return_type T_DOUBLE_ARROW expr + { $$ = Expr\ArrowFunction[['static' => true, 'byRef' => $4, 'params' => $6, 'returnType' => $8, 'expr' => $10, 'attrGroups' => $1]]; } + | attributes T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error + { $$ = Expr\Closure[['static' => false, 'byRef' => $3, 'params' => $5, 'uses' => $7, 'returnType' => $8, 'stmts' => $9, 'attrGroups' => $1]]; } + | attributes T_STATIC T_FUNCTION optional_ref '(' parameter_list ')' lexical_vars optional_return_type block_or_error + { $$ = Expr\Closure[['static' => true, 'byRef' => $4, 'params' => $6, 'uses' => $8, 'returnType' => $9, 'stmts' => $10, 'attrGroups' => $1]]; } +; + +anonymous_class: + optional_attributes T_CLASS ctor_arguments extends_from implements_list '{' class_statement_list '}' + { $$ = array(Stmt\Class_[null, ['type' => 0, 'extends' => $4, 'implements' => $5, 'stmts' => $7, 'attrGroups' => $1]], $3); + $this->checkClass($$[0], -1); } +; + +new_expr: + T_NEW class_name_reference ctor_arguments { $$ = Expr\New_[$2, $3]; } + | T_NEW anonymous_class + { list($class, $ctorArgs) = $2; $$ = Expr\New_[$class, $ctorArgs]; } +; + +lexical_vars: + /* empty */ { $$ = array(); } + | T_USE '(' lexical_var_list ')' { $$ = $3; } +; + +lexical_var_list: + non_empty_lexical_var_list optional_comma { $$ = $1; } +; + +non_empty_lexical_var_list: + lexical_var { init($1); } + | non_empty_lexical_var_list ',' lexical_var { push($1, $3); } +; + +lexical_var: + optional_ref plain_variable { $$ = Expr\ClosureUse[$2, $1]; } +; + +function_call: + name argument_list { $$ = Expr\FuncCall[$1, $2]; } + | callable_expr argument_list { $$ = Expr\FuncCall[$1, $2]; } + | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM member_name argument_list + { $$ = Expr\StaticCall[$1, $3, $4]; } +; + +class_name: + T_STATIC { $$ = Name[$1]; } + | name { $$ = $1; } +; + +name: + T_STRING { $$ = Name[$1]; } + | T_NAME_QUALIFIED { $$ = Name[$1]; } + | T_NAME_FULLY_QUALIFIED { $$ = Name\FullyQualified[substr($1, 1)]; } + | T_NAME_RELATIVE { $$ = Name\Relative[substr($1, 10)]; } +; + +class_name_reference: + class_name { $$ = $1; } + | new_variable { $$ = $1; } + | '(' expr ')' { $$ = $2; } + | error { $$ = Expr\Error[]; $this->errorState = 2; } +; + +class_name_or_var: + class_name { $$ = $1; } + | fully_dereferencable { $$ = $1; } +; + +exit_expr: + /* empty */ { $$ = null; } + | '(' optional_expr ')' { $$ = $2; } +; + +backticks_expr: + /* empty */ { $$ = array(); } + | T_ENCAPSED_AND_WHITESPACE + { $$ = array(Scalar\EncapsedStringPart[Scalar\String_::parseEscapeSequences($1, '`')]); } + | encaps_list { parseEncapsed($1, '`', true); $$ = $1; } +; + +ctor_arguments: + /* empty */ { $$ = array(); } + | argument_list { $$ = $1; } +; + +constant: + name { $$ = Expr\ConstFetch[$1]; } + | T_LINE { $$ = Scalar\MagicConst\Line[]; } + | T_FILE { $$ = Scalar\MagicConst\File[]; } + | T_DIR { $$ = Scalar\MagicConst\Dir[]; } + | T_CLASS_C { $$ = Scalar\MagicConst\Class_[]; } + | T_TRAIT_C { $$ = Scalar\MagicConst\Trait_[]; } + | T_METHOD_C { $$ = Scalar\MagicConst\Method[]; } + | T_FUNC_C { $$ = Scalar\MagicConst\Function_[]; } + | T_NS_C { $$ = Scalar\MagicConst\Namespace_[]; } +; + +class_constant: + class_name_or_var T_PAAMAYIM_NEKUDOTAYIM identifier_ex + { $$ = Expr\ClassConstFetch[$1, $3]; } + /* We interpret an isolated FOO:: as an unfinished class constant fetch. It could also be + an unfinished static property fetch or unfinished scoped call. */ + | class_name_or_var T_PAAMAYIM_NEKUDOTAYIM error + { $$ = Expr\ClassConstFetch[$1, new Expr\Error(stackAttributes(#3))]; $this->errorState = 2; } +; + +array_short_syntax: + '[' array_pair_list ']' + { $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_SHORT; + $$ = new Expr\Array_($2, $attrs); } +; + +dereferencable_scalar: + T_ARRAY '(' array_pair_list ')' + { $attrs = attributes(); $attrs['kind'] = Expr\Array_::KIND_LONG; + $$ = new Expr\Array_($3, $attrs); } + | array_short_syntax { $$ = $1; } + | T_CONSTANT_ENCAPSED_STRING + { $attrs = attributes(); $attrs['kind'] = strKind($1); + $$ = new Scalar\String_(Scalar\String_::parse($1), $attrs); } + | '"' encaps_list '"' + { $attrs = attributes(); $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED; + parseEncapsed($2, '"', true); $$ = new Scalar\Encapsed($2, $attrs); } +; + +scalar: + T_LNUMBER { $$ = $this->parseLNumber($1, attributes()); } + | T_DNUMBER { $$ = Scalar\DNumber[Scalar\DNumber::parse($1)]; } + | dereferencable_scalar { $$ = $1; } + | constant { $$ = $1; } + | class_constant { $$ = $1; } + | T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC + { $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), true); } + | T_START_HEREDOC T_END_HEREDOC + { $$ = $this->parseDocString($1, '', $2, attributes(), stackAttributes(#2), true); } + | T_START_HEREDOC encaps_list T_END_HEREDOC + { $$ = $this->parseDocString($1, $2, $3, attributes(), stackAttributes(#3), true); } +; + +optional_expr: + /* empty */ { $$ = null; } + | expr { $$ = $1; } +; + +fully_dereferencable: + variable { $$ = $1; } + | '(' expr ')' { $$ = $2; } + | dereferencable_scalar { $$ = $1; } + | class_constant { $$ = $1; } +; + +array_object_dereferencable: + fully_dereferencable { $$ = $1; } + | constant { $$ = $1; } +; + +callable_expr: + callable_variable { $$ = $1; } + | '(' expr ')' { $$ = $2; } + | dereferencable_scalar { $$ = $1; } +; + +callable_variable: + simple_variable { $$ = $1; } + | array_object_dereferencable '[' optional_expr ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | array_object_dereferencable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | function_call { $$ = $1; } + | array_object_dereferencable T_OBJECT_OPERATOR property_name argument_list + { $$ = Expr\MethodCall[$1, $3, $4]; } + | array_object_dereferencable T_NULLSAFE_OBJECT_OPERATOR property_name argument_list + { $$ = Expr\NullsafeMethodCall[$1, $3, $4]; } +; + +optional_plain_variable: + /* empty */ { $$ = null; } + | plain_variable { $$ = $1; } +; + +variable: + callable_variable { $$ = $1; } + | static_member { $$ = $1; } + | array_object_dereferencable T_OBJECT_OPERATOR property_name + { $$ = Expr\PropertyFetch[$1, $3]; } + | array_object_dereferencable T_NULLSAFE_OBJECT_OPERATOR property_name + { $$ = Expr\NullsafePropertyFetch[$1, $3]; } +; + +simple_variable: + plain_variable { $$ = $1; } + | '$' '{' expr '}' { $$ = Expr\Variable[$3]; } + | '$' simple_variable { $$ = Expr\Variable[$2]; } + | '$' error { $$ = Expr\Variable[Expr\Error[]]; $this->errorState = 2; } +; + +static_member_prop_name: + simple_variable + { $var = $1->name; $$ = \is_string($var) ? Node\VarLikeIdentifier[$var] : $var; } +; + +static_member: + class_name_or_var T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name + { $$ = Expr\StaticPropertyFetch[$1, $3]; } +; + +new_variable: + simple_variable { $$ = $1; } + | new_variable '[' optional_expr ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | new_variable '{' expr '}' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | new_variable T_OBJECT_OPERATOR property_name { $$ = Expr\PropertyFetch[$1, $3]; } + | new_variable T_NULLSAFE_OBJECT_OPERATOR property_name { $$ = Expr\NullsafePropertyFetch[$1, $3]; } + | class_name T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name + { $$ = Expr\StaticPropertyFetch[$1, $3]; } + | new_variable T_PAAMAYIM_NEKUDOTAYIM static_member_prop_name + { $$ = Expr\StaticPropertyFetch[$1, $3]; } +; + +member_name: + identifier_ex { $$ = $1; } + | '{' expr '}' { $$ = $2; } + | simple_variable { $$ = $1; } +; + +property_name: + identifier { $$ = $1; } + | '{' expr '}' { $$ = $2; } + | simple_variable { $$ = $1; } + | error { $$ = Expr\Error[]; $this->errorState = 2; } +; + +list_expr: + T_LIST '(' inner_array_pair_list ')' { $$ = Expr\List_[$3]; } +; + +array_pair_list: + inner_array_pair_list + { $$ = $1; $end = count($$)-1; if ($$[$end] === null) array_pop($$); } +; + +comma_or_error: + ',' + | error + { /* do nothing -- prevent default action of $$=$1. See #551. */ } +; + +inner_array_pair_list: + inner_array_pair_list comma_or_error array_pair { push($1, $3); } + | array_pair { init($1); } +; + +array_pair: + expr { $$ = Expr\ArrayItem[$1, null, false]; } + | '&' variable { $$ = Expr\ArrayItem[$2, null, true]; } + | list_expr { $$ = Expr\ArrayItem[$1, null, false]; } + | expr T_DOUBLE_ARROW expr { $$ = Expr\ArrayItem[$3, $1, false]; } + | expr T_DOUBLE_ARROW '&' variable { $$ = Expr\ArrayItem[$4, $1, true]; } + | expr T_DOUBLE_ARROW list_expr { $$ = Expr\ArrayItem[$3, $1, false]; } + | T_ELLIPSIS expr { $$ = Expr\ArrayItem[$2, null, false, attributes(), true]; } + | /* empty */ { $$ = null; } +; + +encaps_list: + encaps_list encaps_var { push($1, $2); } + | encaps_list encaps_string_part { push($1, $2); } + | encaps_var { init($1); } + | encaps_string_part encaps_var { init($1, $2); } +; + +encaps_string_part: + T_ENCAPSED_AND_WHITESPACE { $$ = Scalar\EncapsedStringPart[$1]; } +; + +encaps_str_varname: + T_STRING_VARNAME { $$ = Expr\Variable[$1]; } +; + +encaps_var: + plain_variable { $$ = $1; } + | plain_variable '[' encaps_var_offset ']' { $$ = Expr\ArrayDimFetch[$1, $3]; } + | plain_variable T_OBJECT_OPERATOR identifier { $$ = Expr\PropertyFetch[$1, $3]; } + | plain_variable T_NULLSAFE_OBJECT_OPERATOR identifier { $$ = Expr\NullsafePropertyFetch[$1, $3]; } + | T_DOLLAR_OPEN_CURLY_BRACES expr '}' { $$ = Expr\Variable[$2]; } + | T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '}' { $$ = Expr\Variable[$2]; } + | T_DOLLAR_OPEN_CURLY_BRACES encaps_str_varname '[' expr ']' '}' + { $$ = Expr\ArrayDimFetch[$2, $4]; } + | T_CURLY_OPEN variable '}' { $$ = $2; } +; + +encaps_var_offset: + T_STRING { $$ = Scalar\String_[$1]; } + | T_NUM_STRING { $$ = $this->parseNumString($1, attributes()); } + | '-' T_NUM_STRING { $$ = $this->parseNumString('-' . $2, attributes()); } + | plain_variable { $$ = $1; } +; + +%% diff --git a/vendor-bundle/phabel/php-parser/grammar/rebuildParsers.php b/vendor-bundle/phabel/php-parser/grammar/rebuildParsers.php new file mode 100644 index 000000000..4cbb4dd3c --- /dev/null +++ b/vendor-bundle/phabel/php-parser/grammar/rebuildParsers.php @@ -0,0 +1,183 @@ + 'Php5', __DIR__ . '/php7.y' => 'Php7']; +$tokensFile = __DIR__ . '/tokens.y'; +$tokensTemplate = __DIR__ . '/tokens.template'; +$skeletonFile = __DIR__ . '/parser.template'; +$tmpGrammarFile = __DIR__ . '/tmp_parser.phpy'; +$tmpResultFile = __DIR__ . '/tmp_parser.php'; +$resultDir = __DIR__ . '/../lib/PhpParser/Parser'; +$tokensResultsFile = $resultDir . '/Tokens.php'; +$kmyacc = \getenv('KMYACC'); +if (!$kmyacc) { + // Use phpyacc from dev dependencies by default. + $kmyacc = __DIR__ . '/../vendor/bin/phpyacc'; +} +$options = \array_flip($argv); +$optionDebug = isset($options['--debug']); +$optionKeepTmpGrammar = isset($options['--keep-tmp-grammar']); +/////////////////////////////// +/// Utility regex constants /// +/////////////////////////////// +const LIB = '(?(DEFINE) + (?\'[^\\\\\']*+(?:\\\\.[^\\\\\']*+)*+\') + (?"[^\\\\"]*+(?:\\\\.[^\\\\"]*+)*+") + (?(?&singleQuotedString)|(?&doubleQuotedString)) + (?/\\*[^*]*+(?:\\*(?!/)[^*]*+)*+\\*/) + (?\\{[^\'"/{}]*+(?:(?:(?&string)|(?&comment)|(?&code)|/)[^\'"/{}]*+)*+}) +)'; +const PARAMS = '\\[(?[^[\\]]*+(?:\\[(?¶ms)\\][^[\\]]*+)*+)\\]'; +const ARGS = '\\((?[^()]*+(?:\\((?&args)\\)[^()]*+)*+)\\)'; +/////////////////// +/// Main script /// +/////////////////// +$tokens = \file_get_contents($tokensFile); +foreach ($grammarFileToName as $grammarFile => $name) { + echo "Building temporary {$name} grammar file.\n"; + $grammarCode = \file_get_contents($grammarFile); + $grammarCode = \str_replace('%tokens', $tokens, $grammarCode); + $grammarCode = resolveNodes($grammarCode); + $grammarCode = resolveMacros($grammarCode); + $grammarCode = resolveStackAccess($grammarCode); + \file_put_contents($tmpGrammarFile, $grammarCode); + $additionalArgs = $optionDebug ? '-t -v' : ''; + echo "Building {$name} parser.\n"; + $output = execCmd("{$kmyacc} {$additionalArgs} -m {$skeletonFile} -p {$name} {$tmpGrammarFile}"); + $resultCode = \file_get_contents($tmpResultFile); + $resultCode = removeTrailingWhitespace($resultCode); + ensureDirExists($resultDir); + \file_put_contents("{$resultDir}/{$name}.php", $resultCode); + \unlink($tmpResultFile); + echo "Building token definition.\n"; + $output = execCmd("{$kmyacc} -m {$tokensTemplate} {$tmpGrammarFile}"); + \rename($tmpResultFile, $tokensResultsFile); + if (!$optionKeepTmpGrammar) { + \unlink($tmpGrammarFile); + } +} +/////////////////////////////// +/// Preprocessing functions /// +/////////////////////////////// +function resolveNodes($code) +{ + return \preg_replace_callback('~\\b(?[A-Z][a-zA-Z_\\\\]++)\\s*' . \PARAMS . '~', function ($matches) { + // recurse + $matches['params'] = resolveNodes($matches['params']); + $params = magicSplit('(?:' . \PARAMS . '|' . \ARGS . ')(*SKIP)(*FAIL)|,', $matches['params']); + $paramCode = ''; + foreach ($params as $param) { + $paramCode .= $param . ', '; + } + return 'new ' . $matches['name'] . '(' . $paramCode . 'attributes())'; + }, $code); +} +function resolveMacros($code) +{ + return \preg_replace_callback('~\\b(?)(?!array\\()(?[a-z][A-Za-z]++)' . \ARGS . '~', function ($matches) { + // recurse + $matches['args'] = resolveMacros($matches['args']); + $name = $matches['name']; + $args = magicSplit('(?:' . \PARAMS . '|' . \ARGS . ')(*SKIP)(*FAIL)|,', $matches['args']); + if ('attributes' === $name) { + assertArgs(0, $args, $name); + return '$this->startAttributeStack[#1] + $this->endAttributes'; + } + if ('stackAttributes' === $name) { + assertArgs(1, $args, $name); + return '$this->startAttributeStack[' . $args[0] . '] + $this->endAttributeStack[' . $args[0] . ']'; + } + if ('init' === $name) { + return '$$ = array(' . \implode(', ', $args) . ')'; + } + if ('push' === $name) { + assertArgs(2, $args, $name); + return $args[0] . '[] = ' . $args[1] . '; $$ = ' . $args[0]; + } + if ('pushNormalizing' === $name) { + assertArgs(2, $args, $name); + return 'if (is_array(' . $args[1] . ')) { $$ = array_merge(' . $args[0] . ', ' . $args[1] . '); } else { ' . $args[0] . '[] = ' . $args[1] . '; $$ = ' . $args[0] . '; }'; + } + if ('toArray' == $name) { + assertArgs(1, $args, $name); + return 'is_array(' . $args[0] . ') ? ' . $args[0] . ' : array(' . $args[0] . ')'; + } + if ('parseVar' === $name) { + assertArgs(1, $args, $name); + return 'substr(' . $args[0] . ', 1)'; + } + if ('parseEncapsed' === $name) { + assertArgs(3, $args, $name); + return 'foreach (' . $args[0] . ' as $s) { if ($s instanceof Node\\Scalar\\EncapsedStringPart) { $s->value = Node\\Scalar\\String_::parseEscapeSequences($s->value, ' . $args[1] . ', ' . $args[2] . '); } }'; + } + if ('makeNop' === $name) { + assertArgs(3, $args, $name); + return '$startAttributes = ' . $args[1] . '; if (isset($startAttributes[\'comments\'])) { ' . $args[0] . ' = new Stmt\\Nop($startAttributes + ' . $args[2] . '); } else { ' . $args[0] . ' = null; }'; + } + if ('makeZeroLengthNop' == $name) { + assertArgs(2, $args, $name); + return '$startAttributes = ' . $args[1] . '; if (isset($startAttributes[\'comments\'])) { ' . $args[0] . ' = new Stmt\\Nop($this->createCommentNopAttributes($startAttributes[\'comments\'])); } else { ' . $args[0] . ' = null; }'; + } + if ('strKind' === $name) { + assertArgs(1, $args, $name); + return '(' . $args[0] . '[0] === "\'" || (' . $args[0] . '[1] === "\'" && (' . $args[0] . '[0] === \'b\' || ' . $args[0] . '[0] === \'B\')) ? Scalar\\String_::KIND_SINGLE_QUOTED : Scalar\\String_::KIND_DOUBLE_QUOTED)'; + } + if ('prependLeadingComments' === $name) { + assertArgs(1, $args, $name); + return '$attrs = $this->startAttributeStack[#1]; $stmts = ' . $args[0] . '; if (!empty($attrs[\'comments\'])) {$stmts[0]->setAttribute(\'comments\', array_merge($attrs[\'comments\'], $stmts[0]->getAttribute(\'comments\', []))); }'; + } + return $matches[0]; + }, $code); +} +function assertArgs($num, $args, $name) +{ + if ($num != \count($args)) { + die('Wrong argument count for ' . $name . '().'); + } +} +function resolveStackAccess($code) +{ + $code = \preg_replace('/\\$\\d+/', '$this->semStack[$0]', $code); + $code = \preg_replace('/#(\\d+)/', '$$1', $code); + return $code; +} +function removeTrailingWhitespace($code) +{ + $lines = \explode("\n", $code); + $lines = \array_map('rtrim', $lines); + return \implode("\n", $lines); +} +function ensureDirExists($dir) +{ + if (!\is_dir($dir)) { + \mkdir($dir, 0777, \true); + } +} +function execCmd($cmd) +{ + $output = \trim(\shell_exec("{$cmd} 2>&1")); + if ($output !== "") { + echo "> " . $cmd . "\n"; + echo $output; + } + return $output; +} +////////////////////////////// +/// Regex helper functions /// +////////////////////////////// +function regex($regex) +{ + return '~' . \LIB . '(?:' . \str_replace('~', '\\~', $regex) . ')~'; +} +function magicSplit($regex, $string) +{ + $pieces = \preg_split(regex('(?:(?&string)|(?&comment)|(?&code))(*SKIP)(*FAIL)|' . $regex), $string); + foreach ($pieces as &$piece) { + $piece = \trim($piece); + } + if ($pieces === ['']) { + return []; + } + return $pieces; +} diff --git a/vendor-bundle/phabel/php-parser/grammar/tokens.template b/vendor-bundle/phabel/php-parser/grammar/tokens.template new file mode 100644 index 000000000..ba4e4901c --- /dev/null +++ b/vendor-bundle/phabel/php-parser/grammar/tokens.template @@ -0,0 +1,17 @@ +semValue +#semval($,%t) $this->semValue +#semval(%n) $this->stackPos-(%l-%n) +#semval(%n,%t) $this->stackPos-(%l-%n) + +namespace PhpParser\Parser; +#include; + +/* GENERATED file based on grammar/tokens.y */ +final class Tokens +{ +#tokenval + const %s = %n; +#endtokenval +} diff --git a/vendor-bundle/phabel/php-parser/grammar/tokens.y b/vendor-bundle/phabel/php-parser/grammar/tokens.y new file mode 100644 index 000000000..b0b0360cd --- /dev/null +++ b/vendor-bundle/phabel/php-parser/grammar/tokens.y @@ -0,0 +1,113 @@ +/* We currently rely on the token ID mapping to be the same between PHP 5 and PHP 7 - so the same lexer can be used for + * both. This is enforced by sharing this token file. */ + +%right T_THROW +%left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE +%left ',' +%left T_LOGICAL_OR +%left T_LOGICAL_XOR +%left T_LOGICAL_AND +%right T_PRINT +%right T_YIELD +%right T_DOUBLE_ARROW +%right T_YIELD_FROM +%left '=' T_PLUS_EQUAL T_MINUS_EQUAL T_MUL_EQUAL T_DIV_EQUAL T_CONCAT_EQUAL T_MOD_EQUAL T_AND_EQUAL T_OR_EQUAL T_XOR_EQUAL T_SL_EQUAL T_SR_EQUAL T_POW_EQUAL T_COALESCE_EQUAL +%left '?' ':' +%right T_COALESCE +%left T_BOOLEAN_OR +%left T_BOOLEAN_AND +%left '|' +%left '^' +%left '&' +%nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL T_SPACESHIP +%nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL +%left T_SL T_SR +%left '+' '-' '.' +%left '*' '/' '%' +%right '!' +%nonassoc T_INSTANCEOF +%right '~' T_INC T_DEC T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_ARRAY_CAST T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@' +%right T_POW +%right '[' +%nonassoc T_NEW T_CLONE +%token T_EXIT +%token T_IF +%left T_ELSEIF +%left T_ELSE +%left T_ENDIF +%token T_LNUMBER +%token T_DNUMBER +%token T_STRING +%token T_STRING_VARNAME +%token T_VARIABLE +%token T_NUM_STRING +%token T_INLINE_HTML +%token T_ENCAPSED_AND_WHITESPACE +%token T_CONSTANT_ENCAPSED_STRING +%token T_ECHO +%token T_DO +%token T_WHILE +%token T_ENDWHILE +%token T_FOR +%token T_ENDFOR +%token T_FOREACH +%token T_ENDFOREACH +%token T_DECLARE +%token T_ENDDECLARE +%token T_AS +%token T_SWITCH +%token T_MATCH +%token T_ENDSWITCH +%token T_CASE +%token T_DEFAULT +%token T_BREAK +%token T_CONTINUE +%token T_GOTO +%token T_FUNCTION +%token T_FN +%token T_CONST +%token T_RETURN +%token T_TRY +%token T_CATCH +%token T_FINALLY +%token T_THROW +%token T_USE +%token T_INSTEADOF +%token T_GLOBAL +%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC +%token T_VAR +%token T_UNSET +%token T_ISSET +%token T_EMPTY +%token T_HALT_COMPILER +%token T_CLASS +%token T_TRAIT +%token T_INTERFACE +%token T_EXTENDS +%token T_IMPLEMENTS +%token T_OBJECT_OPERATOR +%token T_NULLSAFE_OBJECT_OPERATOR +%token T_DOUBLE_ARROW +%token T_LIST +%token T_ARRAY +%token T_CALLABLE +%token T_CLASS_C +%token T_TRAIT_C +%token T_METHOD_C +%token T_FUNC_C +%token T_LINE +%token T_FILE +%token T_START_HEREDOC +%token T_END_HEREDOC +%token T_DOLLAR_OPEN_CURLY_BRACES +%token T_CURLY_OPEN +%token T_PAAMAYIM_NEKUDOTAYIM +%token T_NAMESPACE +%token T_NS_C +%token T_DIR +%token T_NS_SEPARATOR +%token T_ELLIPSIS +%token T_NAME_FULLY_QUALIFIED +%token T_NAME_QUALIFIED +%token T_NAME_RELATIVE +%token T_ATTRIBUTE \ No newline at end of file diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder.php new file mode 100644 index 000000000..bab0ecf9e --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder.php @@ -0,0 +1,13 @@ +name = $name; + } + /** + * Extends a class. + * + * @param Name|string $class Name of class to extend + * + * @return $this The builder instance (for fluid interface) + */ + public function extend($class) + { + $this->extends = BuilderHelpers::normalizeName($class); + return $this; + } + /** + * Implements one or more interfaces. + * + * @param Name|string ...$interfaces Names of interfaces to implement + * + * @return $this The builder instance (for fluid interface) + */ + public function implement(...$interfaces) + { + foreach ($interfaces as $interface) { + $this->implements[] = BuilderHelpers::normalizeName($interface); + } + return $this; + } + /** + * Makes the class abstract. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeAbstract() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_ABSTRACT); + return $this; + } + /** + * Makes the class final. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeFinal() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_FINAL); + return $this; + } + /** + * Adds a statement. + * + * @param Stmt|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $stmt = BuilderHelpers::normalizeNode($stmt); + $targets = [Stmt\TraitUse::class => &$this->uses, Stmt\ClassConst::class => &$this->constants, Stmt\Property::class => &$this->properties, Stmt\ClassMethod::class => &$this->methods]; + $class = \get_class($stmt); + if (!isset($targets[$class])) { + throw new \LogicException(\sprintf('Unexpected node of type "%s"', $stmt->getType())); + } + $targets[$class][] = $stmt; + return $this; + } + /** + * Returns the built class node. + * + * @return Stmt\Class_ The built class node + */ + public function getNode() + { + $phabelReturn = new Stmt\Class_($this->name, ['flags' => $this->flags, 'extends' => $this->extends, 'implements' => $this->implements, 'stmts' => \array_merge($this->uses, $this->constants, $this->properties, $this->methods)], $this->attributes); + if (!$phabelReturn instanceof PhpParser\Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type PhpParser\\Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Declaration.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Declaration.php new file mode 100644 index 000000000..53b2d7022 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Declaration.php @@ -0,0 +1,37 @@ +addStmt($stmt); + } + return $this; + } + /** + * Sets doc comment for the declaration. + * + * @param PhpParser\Comment\Doc|string $docComment Doc comment to set + * + * @return $this The builder instance (for fluid interface) + */ + public function setDocComment($docComment) + { + $this->attributes['comments'] = [BuilderHelpers::normalizeDocComment($docComment)]; + return $this; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/FunctionLike.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/FunctionLike.php new file mode 100644 index 000000000..242238c83 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/FunctionLike.php @@ -0,0 +1,66 @@ +returnByRef = \true; + return $this; + } + /** + * Adds a parameter. + * + * @param Node\Param|Param $param The parameter to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addParam($param) + { + $param = BuilderHelpers::normalizeNode($param); + if (!$param instanceof Node\Param) { + throw new \LogicException(\sprintf('Expected parameter node, got "%s"', $param->getType())); + } + $this->params[] = $param; + return $this; + } + /** + * Adds multiple parameters. + * + * @param array $params The parameters to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addParams(array $params) + { + foreach ($params as $param) { + $this->addParam($param); + } + return $this; + } + /** + * Sets the return type for PHP 7. + * + * @param string|Node\Name|Node\NullableType $type One of array, callable, string, int, float, + * bool, iterable, or a class/interface name. + * + * @return $this The builder instance (for fluid interface) + */ + public function setReturnType($type) + { + $this->returnType = BuilderHelpers::normalizeType($type); + return $this; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Function_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Function_.php new file mode 100644 index 000000000..bfbb1a9b0 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Function_.php @@ -0,0 +1,54 @@ +name = $name; + } + /** + * Adds a statement. + * + * @param Node|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $this->stmts[] = BuilderHelpers::normalizeStmt($stmt); + return $this; + } + /** + * Returns the built function node. + * + * @return Stmt\Function_ The built function node + */ + public function getNode() + { + $phabelReturn = new Stmt\Function_($this->name, ['byRef' => $this->returnByRef, 'params' => $this->params, 'returnType' => $this->returnType, 'stmts' => $this->stmts], $this->attributes); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Interface_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Interface_.php new file mode 100644 index 000000000..611f54b3f --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Interface_.php @@ -0,0 +1,79 @@ +name = $name; + } + /** + * Extends one or more interfaces. + * + * @param Name|string ...$interfaces Names of interfaces to extend + * + * @return $this The builder instance (for fluid interface) + */ + public function extend(...$interfaces) + { + foreach ($interfaces as $interface) { + $this->extends[] = BuilderHelpers::normalizeName($interface); + } + return $this; + } + /** + * Adds a statement. + * + * @param Stmt|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $stmt = BuilderHelpers::normalizeNode($stmt); + if ($stmt instanceof Stmt\ClassConst) { + $this->constants[] = $stmt; + } elseif ($stmt instanceof Stmt\ClassMethod) { + // we erase all statements in the body of an interface method + $stmt->stmts = null; + $this->methods[] = $stmt; + } else { + throw new \LogicException(\sprintf('Unexpected node of type "%s"', $stmt->getType())); + } + return $this; + } + /** + * Returns the built interface node. + * + * @return Stmt\Interface_ The built interface node + */ + public function getNode() + { + $phabelReturn = new Stmt\Interface_($this->name, ['extends' => $this->extends, 'stmts' => \array_merge($this->constants, $this->methods)], $this->attributes); + if (!$phabelReturn instanceof PhpParser\Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type PhpParser\\Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Method.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Method.php new file mode 100644 index 000000000..d5f74d761 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Method.php @@ -0,0 +1,124 @@ +name = $name; + } + /** + * Makes the method public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PUBLIC); + return $this; + } + /** + * Makes the method protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PROTECTED); + return $this; + } + /** + * Makes the method private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PRIVATE); + return $this; + } + /** + * Makes the method static. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeStatic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_STATIC); + return $this; + } + /** + * Makes the method abstract. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeAbstract() + { + if (!empty($this->stmts)) { + throw new \LogicException('Cannot make method with statements abstract'); + } + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_ABSTRACT); + $this->stmts = null; + // abstract methods don't have statements + return $this; + } + /** + * Makes the method final. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeFinal() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_FINAL); + return $this; + } + /** + * Adds a statement. + * + * @param Node|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + if (null === $this->stmts) { + throw new \LogicException('Cannot add statements to an abstract method'); + } + $this->stmts[] = BuilderHelpers::normalizeStmt($stmt); + return $this; + } + /** + * Returns the built method node. + * + * @return Stmt\ClassMethod The built method node + */ + public function getNode() + { + $phabelReturn = new Stmt\ClassMethod($this->name, ['flags' => $this->flags, 'byRef' => $this->returnByRef, 'params' => $this->params, 'returnType' => $this->returnType, 'stmts' => $this->stmts], $this->attributes); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Namespace_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Namespace_.php new file mode 100644 index 000000000..6e144289d --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Namespace_.php @@ -0,0 +1,47 @@ +name = null !== $name ? BuilderHelpers::normalizeName($name) : null; + } + /** + * Adds a statement. + * + * @param Node|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $this->stmts[] = BuilderHelpers::normalizeStmt($stmt); + return $this; + } + /** + * Returns the built node. + * + * @return Stmt\Namespace_ The built node + */ + public function getNode() + { + $phabelReturn = new Stmt\Namespace_($this->name, $this->stmts, $this->attributes); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Param.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Param.php new file mode 100644 index 000000000..492d4146e --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Param.php @@ -0,0 +1,105 @@ +name = $name; + } + /** + * Sets default value for the parameter. + * + * @param mixed $value Default value to use + * + * @return $this The builder instance (for fluid interface) + */ + public function setDefault($value) + { + $this->default = BuilderHelpers::normalizeValue($value); + return $this; + } + /** + * Sets type for the parameter. + * + * @param string|Node\Name|Node\NullableType|Node\UnionType $type Parameter type + * + * @return $this The builder instance (for fluid interface) + */ + public function setType($type) + { + $this->type = BuilderHelpers::normalizeType($type); + if ($this->type == 'void') { + throw new \LogicException('Parameter type cannot be void'); + } + return $this; + } + /** + * Sets type for the parameter. + * + * @param string|Node\Name|Node\NullableType|Node\UnionType $type Parameter type + * + * @return $this The builder instance (for fluid interface) + * + * @deprecated Use setType() instead + */ + public function setTypeHint($type) + { + return $this->setType($type); + } + /** + * Make the parameter accept the value by reference. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeByRef() + { + $this->byRef = \true; + return $this; + } + /** + * Make the parameter variadic + * + * @return $this The builder instance (for fluid interface) + */ + public function makeVariadic() + { + $this->variadic = \true; + return $this; + } + /** + * Returns the built parameter node. + * + * @return Node\Param The built parameter node + */ + public function getNode() + { + $phabelReturn = new Node\Param(new Node\Expr\Variable($this->name), $this->default, $this->type, $this->byRef, $this->variadic); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Property.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Property.php new file mode 100644 index 000000000..0b9cac9cb --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Property.php @@ -0,0 +1,124 @@ +name = $name; + } + /** + * Makes the property public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PUBLIC); + return $this; + } + /** + * Makes the property protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PROTECTED); + return $this; + } + /** + * Makes the property private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PRIVATE); + return $this; + } + /** + * Makes the property static. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeStatic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_STATIC); + return $this; + } + /** + * Sets default value for the property. + * + * @param mixed $value Default value to use + * + * @return $this The builder instance (for fluid interface) + */ + public function setDefault($value) + { + $this->default = BuilderHelpers::normalizeValue($value); + return $this; + } + /** + * Sets doc comment for the property. + * + * @param PhpParser\Comment\Doc|string $docComment Doc comment to set + * + * @return $this The builder instance (for fluid interface) + */ + public function setDocComment($docComment) + { + $this->attributes = ['comments' => [BuilderHelpers::normalizeDocComment($docComment)]]; + return $this; + } + /** + * Sets the property type for PHP 7.4+. + * + * @param string|Name|NullableType|Identifier $type + * + * @return $this + */ + public function setType($type) + { + $this->type = BuilderHelpers::normalizeType($type); + return $this; + } + /** + * Returns the built class node. + * + * @return Stmt\Property The built property node + */ + public function getNode() + { + $phabelReturn = new Stmt\Property($this->flags !== 0 ? $this->flags : Stmt\Class_::MODIFIER_PUBLIC, [new Stmt\PropertyProperty($this->name, $this->default)], $this->attributes, $this->type); + if (!$phabelReturn instanceof PhpParser\Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type PhpParser\\Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/TraitUse.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/TraitUse.php new file mode 100644 index 000000000..c7c35c8f3 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/TraitUse.php @@ -0,0 +1,65 @@ +and($trait); + } + } + /** + * Adds used trait. + * + * @param Node\Name|string $trait Trait name + * + * @return $this The builder instance (for fluid interface) + */ + public function and($trait) + { + $this->traits[] = BuilderHelpers::normalizeName($trait); + return $this; + } + /** + * Adds trait adaptation. + * + * @param Stmt\TraitUseAdaptation|Builder\TraitUseAdaptation $adaptation Trait adaptation + * + * @return $this The builder instance (for fluid interface) + */ + public function with($adaptation) + { + $adaptation = BuilderHelpers::normalizeNode($adaptation); + if (!$adaptation instanceof Stmt\TraitUseAdaptation) { + throw new \LogicException('Adaptation must have type TraitUseAdaptation'); + } + $this->adaptations[] = $adaptation; + return $this; + } + /** + * Returns the built node. + * + * @return Node The built node + */ + public function getNode() + { + $phabelReturn = new Stmt\TraitUse($this->traits, $this->adaptations); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php new file mode 100644 index 000000000..ce07df076 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php @@ -0,0 +1,150 @@ +type = self::TYPE_UNDEFINED; + $this->trait = \is_null($trait) ? null : BuilderHelpers::normalizeName($trait); + $this->method = BuilderHelpers::normalizeIdentifier($method); + } + /** + * Sets alias of method. + * + * @param Node\Identifier|string $alias Alias for adaptated method + * + * @return $this The builder instance (for fluid interface) + */ + public function as($alias) + { + if ($this->type === self::TYPE_UNDEFINED) { + $this->type = self::TYPE_ALIAS; + } + if ($this->type !== self::TYPE_ALIAS) { + throw new \LogicException('Cannot set alias for not alias adaptation buider'); + } + $this->alias = $alias; + return $this; + } + /** + * Sets adaptated method public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->setModifier(Stmt\Class_::MODIFIER_PUBLIC); + return $this; + } + /** + * Sets adaptated method protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->setModifier(Stmt\Class_::MODIFIER_PROTECTED); + return $this; + } + /** + * Sets adaptated method private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->setModifier(Stmt\Class_::MODIFIER_PRIVATE); + return $this; + } + /** + * Adds overwritten traits. + * + * @param Node\Name|string ...$traits Traits for overwrite + * + * @return $this The builder instance (for fluid interface) + */ + public function insteadof(...$traits) + { + if ($this->type === self::TYPE_UNDEFINED) { + if (\is_null($this->trait)) { + throw new \LogicException('Precedence adaptation must have trait'); + } + $this->type = self::TYPE_PRECEDENCE; + } + if ($this->type !== self::TYPE_PRECEDENCE) { + throw new \LogicException('Cannot add overwritten traits for not precedence adaptation buider'); + } + foreach ($traits as $trait) { + $this->insteadof[] = BuilderHelpers::normalizeName($trait); + } + return $this; + } + protected function setModifier($modifier) + { + if (!\is_int($modifier)) { + if (!(\is_bool($modifier) || \is_numeric($modifier))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($modifier) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($modifier) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $modifier = (int) $modifier; + } + } + if ($this->type === self::TYPE_UNDEFINED) { + $this->type = self::TYPE_ALIAS; + } + if ($this->type !== self::TYPE_ALIAS) { + throw new \LogicException('Cannot set access modifier for not alias adaptation buider'); + } + if (\is_null($this->modifier)) { + $this->modifier = $modifier; + } else { + throw new \LogicException('Multiple access type modifiers are not allowed'); + } + } + /** + * Returns the built node. + * + * @return Node The built node + */ + public function getNode() + { + switch ($this->type) { + case self::TYPE_ALIAS: + $phabelReturn = new Stmt\TraitUseAdaptation\Alias($this->trait, $this->method, $this->modifier, $this->alias); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + case self::TYPE_PRECEDENCE: + $phabelReturn = new Stmt\TraitUseAdaptation\Precedence($this->trait, $this->method, $this->insteadof); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + default: + throw new \LogicException('Type of adaptation is not defined'); + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Trait_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Trait_.php new file mode 100644 index 000000000..b40037e97 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Trait_.php @@ -0,0 +1,64 @@ +name = $name; + } + /** + * Adds a statement. + * + * @param Stmt|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $stmt = BuilderHelpers::normalizeNode($stmt); + if ($stmt instanceof Stmt\Property) { + $this->properties[] = $stmt; + } elseif ($stmt instanceof Stmt\ClassMethod) { + $this->methods[] = $stmt; + } elseif ($stmt instanceof Stmt\TraitUse) { + $this->uses[] = $stmt; + } else { + throw new \LogicException(\sprintf('Unexpected node of type "%s"', $stmt->getType())); + } + return $this; + } + /** + * Returns the built trait node. + * + * @return Stmt\Trait_ The built interface node + */ + public function getNode() + { + $phabelReturn = new Stmt\Trait_($this->name, ['stmts' => \array_merge($this->uses, $this->properties, $this->methods)], $this->attributes); + if (!$phabelReturn instanceof PhpParser\Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type PhpParser\\Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Use_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Use_.php new file mode 100644 index 000000000..2c62af409 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Builder/Use_.php @@ -0,0 +1,64 @@ +name = BuilderHelpers::normalizeName($name); + $this->type = $type; + } + /** + * Sets alias for used name. + * + * @param string $alias Alias to use (last component of full name by default) + * + * @return $this The builder instance (for fluid interface) + */ + public function as($alias) + { + if (!\is_string($alias)) { + if (!(\is_string($alias) || \is_object($alias) && \method_exists($alias, '__toString') || (\is_bool($alias) || \is_numeric($alias)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($alias) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($alias) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $alias = (string) $alias; + } + } + $this->alias = $alias; + return $this; + } + /** + * Returns the built node. + * + * @return Stmt\Use_ The built node + */ + public function getNode() + { + $phabelReturn = new Stmt\Use_([new Stmt\UseUse($this->name, $this->alias)], $this->type); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/BuilderFactory.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/BuilderFactory.php new file mode 100644 index 000000000..01df4f711 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/BuilderFactory.php @@ -0,0 +1,480 @@ +args($args)); + if (!$phabelReturn instanceof Expr\FuncCall) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr\\FuncCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Creates a method call node. + * + * @param Expr $var Variable the method is called on + * @param string|Identifier|Expr $name Method name + * @param array $args Method arguments + * + * @return Expr\MethodCall + */ + public function methodCall(Expr $var, $name, array $args = []) + { + $phabelReturn = new Expr\MethodCall($var, BuilderHelpers::normalizeIdentifierOrExpr($name), $this->args($args)); + if (!$phabelReturn instanceof Expr\MethodCall) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr\\MethodCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Creates a static method call node. + * + * @param string|Name|Expr $class Class name + * @param string|Identifier|Expr $name Method name + * @param array $args Method arguments + * + * @return Expr\StaticCall + */ + public function staticCall($class, $name, array $args = []) + { + $phabelReturn = new Expr\StaticCall(BuilderHelpers::normalizeNameOrExpr($class), BuilderHelpers::normalizeIdentifierOrExpr($name), $this->args($args)); + if (!$phabelReturn instanceof Expr\StaticCall) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr\\StaticCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Creates an object creation node. + * + * @param string|Name|Expr $class Class name + * @param array $args Constructor arguments + * + * @return Expr\New_ + */ + public function new($class, array $args = []) + { + $phabelReturn = new Expr\New_(BuilderHelpers::normalizeNameOrExpr($class), $this->args($args)); + if (!$phabelReturn instanceof Expr\New_) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr\\New_, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Creates a constant fetch node. + * + * @param string|Name $name Constant name + * + * @return Expr\ConstFetch + */ + public function constFetch($name) + { + $phabelReturn = new Expr\ConstFetch(BuilderHelpers::normalizeName($name)); + if (!$phabelReturn instanceof Expr\ConstFetch) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr\\ConstFetch, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Creates a property fetch node. + * + * @param Expr $var Variable holding object + * @param string|Identifier|Expr $name Property name + * + * @return Expr\PropertyFetch + */ + public function propertyFetch(Expr $var, $name) + { + $phabelReturn = new Expr\PropertyFetch($var, BuilderHelpers::normalizeIdentifierOrExpr($name)); + if (!$phabelReturn instanceof Expr\PropertyFetch) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr\\PropertyFetch, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Creates a class constant fetch node. + * + * @param string|Name|Expr $class Class name + * @param string|Identifier $name Constant name + * + * @return Expr\ClassConstFetch + */ + public function classConstFetch($class, $name) + { + $phabelReturn = new Expr\ClassConstFetch(BuilderHelpers::normalizeNameOrExpr($class), BuilderHelpers::normalizeIdentifier($name)); + if (!$phabelReturn instanceof Expr\ClassConstFetch) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr\\ClassConstFetch, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Creates nested Concat nodes from a list of expressions. + * + * @param Expr|string ...$exprs Expressions or literal strings + * + * @return Concat + */ + public function concat(...$exprs) + { + $numExprs = \count($exprs); + if ($numExprs < 2) { + throw new \LogicException('Expected at least two expressions'); + } + $lastConcat = $this->normalizeStringExpr($exprs[0]); + for ($i = 1; $i < $numExprs; $i++) { + $lastConcat = new Concat($lastConcat, $this->normalizeStringExpr($exprs[$i])); + } + $phabelReturn = $lastConcat; + if (!$phabelReturn instanceof Concat) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Concat, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string|Expr $expr + * @return Expr + */ + private function normalizeStringExpr($expr) + { + if ($expr instanceof Expr) { + $phabelReturn = $expr; + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if (\is_string($expr)) { + $phabelReturn = new String_($expr); + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + throw new \LogicException('Expected string or Expr'); + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/BuilderHelpers.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/BuilderHelpers.php new file mode 100644 index 000000000..acf8089e3 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/BuilderHelpers.php @@ -0,0 +1,349 @@ +getNode(); + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } elseif ($node instanceof Node) { + $phabelReturn = $node; + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + throw new \LogicException('Expected node or builder object'); + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** + * Normalizes a node to a statement. + * + * Expressions are wrapped in a Stmt\Expression node. + * + * @param Node|Builder $node The node to normalize + * + * @return Stmt The normalized statement node + */ + public static function normalizeStmt($node) + { + $node = self::normalizeNode($node); + if ($node instanceof Stmt) { + $phabelReturn = $node; + if (!$phabelReturn instanceof Stmt) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Stmt, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($node instanceof Expr) { + $phabelReturn = new Stmt\Expression($node); + if (!$phabelReturn instanceof Stmt) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Stmt, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + throw new \LogicException('Expected statement or expression node'); + throw new \TypeError(__METHOD__ . '(): Return value must be of type Stmt, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** + * Normalizes strings to Identifier. + * + * @param string|Identifier $name The identifier to normalize + * + * @return Identifier The normalized identifier + */ + public static function normalizeIdentifier($name) + { + if ($name instanceof Identifier) { + $phabelReturn = $name; + if (!$phabelReturn instanceof Identifier) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Identifier, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if (\is_string($name)) { + $phabelReturn = new Identifier($name); + if (!$phabelReturn instanceof Identifier) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Identifier, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + throw new \LogicException('Phabel\\Expected string or instance of Node\\Identifier'); + throw new \TypeError(__METHOD__ . '(): Return value must be of type Identifier, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** + * Normalizes strings to Identifier, also allowing expressions. + * + * @param string|Identifier|Expr $name The identifier to normalize + * + * @return Identifier|Expr The normalized identifier or expression + */ + public static function normalizeIdentifierOrExpr($name) + { + if ($name instanceof Identifier || $name instanceof Expr) { + return $name; + } + if (\is_string($name)) { + return new Identifier($name); + } + throw new \LogicException('Phabel\\Expected string or instance of Node\\Identifier or Node\\Expr'); + } + /** + * Normalizes a name: Converts string names to Name nodes. + * + * @param Name|string $name The name to normalize + * + * @return Name The normalized name + */ + public static function normalizeName($name) + { + $phabelReturn = self::normalizeNameCommon($name, \false); + if (!$phabelReturn instanceof Name) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Name, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Normalizes a name: Converts string names to Name nodes, while also allowing expressions. + * + * @param Expr|Name|string $name The name to normalize + * + * @return Name|Expr The normalized name or expression + */ + public static function normalizeNameOrExpr($name) + { + return self::normalizeNameCommon($name, \true); + } + /** + * Normalizes a name: Converts string names to Name nodes, optionally allowing expressions. + * + * @param Expr|Name|string $name The name to normalize + * @param bool $allowExpr Whether to also allow expressions + * + * @return Name|Expr The normalized name, or expression (if allowed) + */ + private static function normalizeNameCommon($name, $allowExpr) + { + if (!\is_bool($allowExpr)) { + if (!(\is_bool($allowExpr) || \is_numeric($allowExpr) || \is_string($allowExpr))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($allowExpr) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($allowExpr) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $allowExpr = (bool) $allowExpr; + } + } + if ($name instanceof Name) { + return $name; + } elseif (\is_string($name)) { + if (!$name) { + throw new \LogicException('Name cannot be empty'); + } + if ($name[0] === '\\') { + return new Name\FullyQualified(\substr($name, 1)); + } elseif (0 === \strpos($name, 'namespace\\')) { + return new Name\Relative(\substr($name, \strlen('namespace\\'))); + } else { + return new Name($name); + } + } + if ($allowExpr) { + if ($name instanceof Expr) { + return $name; + } + throw new \LogicException('Phabel\\Name must be a string or an instance of Node\\Name or Node\\Expr'); + } else { + throw new \LogicException('Phabel\\Name must be a string or an instance of Node\\Name'); + } + } + /** + * Normalizes a type: Converts plain-text type names into proper AST representation. + * + * In particular, builtin types become Identifiers, custom types become Names and nullables + * are wrapped in NullableType nodes. + * + * @param string|Name|Identifier|NullableType|UnionType $type The type to normalize + * + * @return Name|Identifier|NullableType|UnionType The normalized type + */ + public static function normalizeType($type) + { + if (!\is_string($type)) { + if (!$type instanceof Name && !$type instanceof Identifier && !$type instanceof NullableType && !$type instanceof UnionType) { + throw new \LogicException('Type must be a string, or an instance of Name, Identifier, NullableType or UnionType'); + } + return $type; + } + $nullable = \false; + if (\strlen($type) > 0 && $type[0] === '?') { + $nullable = \true; + $type = \substr($type, 1); + } + $builtinTypes = ['array', 'callable', 'string', 'int', 'float', 'bool', 'iterable', 'void', 'object', 'mixed']; + $lowerType = \strtolower($type); + if (\in_array($lowerType, $builtinTypes)) { + $type = new Identifier($lowerType); + } else { + $type = self::normalizeName($type); + } + if ($nullable && (string) $type === 'void') { + throw new \LogicException('void type cannot be nullable'); + } + if ($nullable && (string) $type === 'mixed') { + throw new \LogicException('mixed type cannot be nullable'); + } + return $nullable ? new NullableType($type) : $type; + } + /** + * Normalizes a value: Converts nulls, booleans, integers, + * floats, strings and arrays into their respective nodes + * + * @param Node\Expr|bool|null|int|float|string|array $value The value to normalize + * + * @return Expr The normalized value + */ + public static function normalizeValue($value) + { + if ($value instanceof Node\Expr) { + $phabelReturn = $value; + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } elseif (\is_null($value)) { + $phabelReturn = new Expr\ConstFetch(new Name('null')); + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } elseif (\is_bool($value)) { + $phabelReturn = new Expr\ConstFetch(new Name($value ? 'true' : 'false')); + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } elseif (\is_int($value)) { + $phabelReturn = new Scalar\LNumber($value); + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } elseif (\is_float($value)) { + $phabelReturn = new Scalar\DNumber($value); + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } elseif (\is_string($value)) { + $phabelReturn = new Scalar\String_($value); + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } elseif (\is_array($value)) { + $items = []; + $lastKey = -1; + foreach ($value as $itemKey => $itemValue) { + // for consecutive, numeric keys don't generate keys + if (null !== $lastKey && ++$lastKey === $itemKey) { + $items[] = new Expr\ArrayItem(self::normalizeValue($itemValue)); + } else { + $lastKey = null; + $items[] = new Expr\ArrayItem(self::normalizeValue($itemValue), self::normalizeValue($itemKey)); + } + } + $phabelReturn = new Expr\Array_($items); + if (!$phabelReturn instanceof Expr) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } else { + throw new \LogicException('Invalid value'); + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** + * Normalizes a doc comment: Converts plain strings to PhpParser\Comment\Doc. + * + * @param Comment\Doc|string $docComment The doc comment to normalize + * + * @return Comment\Doc The normalized doc comment + */ + public static function normalizeDocComment($docComment) + { + if ($docComment instanceof Comment\Doc) { + $phabelReturn = $docComment; + if (!$phabelReturn instanceof Comment\Doc) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Comment\\Doc, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } elseif (\is_string($docComment)) { + $phabelReturn = new Comment\Doc($docComment); + if (!$phabelReturn instanceof Comment\Doc) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Comment\\Doc, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } else { + throw new \LogicException('Phabel\\Doc comment must be a string or an instance of PhpParser\\Comment\\Doc'); + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type Comment\\Doc, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** + * Adds a modifier and returns new modifier bitmask. + * + * @param int $modifiers Existing modifiers + * @param int $modifier Modifier to set + * + * @return int New modifiers + */ + public static function addModifier($modifiers, $modifier) + { + if (!\is_int($modifiers)) { + if (!(\is_bool($modifiers) || \is_numeric($modifiers))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($modifiers) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($modifiers) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $modifiers = (int) $modifiers; + } + } + if (!\is_int($modifier)) { + if (!(\is_bool($modifier) || \is_numeric($modifier))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($modifier) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($modifier) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $modifier = (int) $modifier; + } + } + Stmt\Class_::verifyModifier($modifiers, $modifier); + $phabelReturn = $modifiers | $modifier; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Comment.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Comment.php new file mode 100644 index 000000000..ab46bee18 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Comment.php @@ -0,0 +1,390 @@ +text = $text; + $this->startLine = $startLine; + $this->startFilePos = $startFilePos; + $this->startTokenPos = $startTokenPos; + $this->endLine = $endLine; + $this->endFilePos = $endFilePos; + $this->endTokenPos = $endTokenPos; + } + /** + * Gets the comment text. + * + * @return string The comment text (including comment delimiters like /*) + */ + public function getText() + { + $phabelReturn = $this->text; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the line number the comment started on. + * + * @return int Line number (or -1 if not available) + */ + public function getStartLine() + { + $phabelReturn = $this->startLine; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the file offset the comment started on. + * + * @return int File offset (or -1 if not available) + */ + public function getStartFilePos() + { + $phabelReturn = $this->startFilePos; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the token offset the comment started on. + * + * @return int Token offset (or -1 if not available) + */ + public function getStartTokenPos() + { + $phabelReturn = $this->startTokenPos; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the line number the comment ends on. + * + * @return int Line number (or -1 if not available) + */ + public function getEndLine() + { + $phabelReturn = $this->endLine; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the file offset the comment ends on. + * + * @return int File offset (or -1 if not available) + */ + public function getEndFilePos() + { + $phabelReturn = $this->endFilePos; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the token offset the comment ends on. + * + * @return int Token offset (or -1 if not available) + */ + public function getEndTokenPos() + { + $phabelReturn = $this->endTokenPos; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the line number the comment started on. + * + * @deprecated Use getStartLine() instead + * + * @return int Line number + */ + public function getLine() + { + $phabelReturn = $this->startLine; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the file offset the comment started on. + * + * @deprecated Use getStartFilePos() instead + * + * @return int File offset + */ + public function getFilePos() + { + $phabelReturn = $this->startFilePos; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the token offset the comment started on. + * + * @deprecated Use getStartTokenPos() instead + * + * @return int Token offset + */ + public function getTokenPos() + { + $phabelReturn = $this->startTokenPos; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the comment text. + * + * @return string The comment text (including comment delimiters like /*) + */ + public function __toString() + { + $phabelReturn = $this->text; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the reformatted comment text. + * + * "Reformatted" here means that we try to clean up the whitespace at the + * starts of the lines. This is necessary because we receive the comments + * without trailing whitespace on the first line, but with trailing whitespace + * on all subsequent lines. + * + * @return mixed|string + */ + public function getReformattedText() + { + $text = \trim($this->text); + $newlinePos = \strpos($text, "\n"); + if (\false === $newlinePos) { + // Single line comments don't need further processing + return $text; + } elseif (\preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\\R\\s+\\*.*)+$)', $text)) { + // Multi line comment of the type + // + // /* + // * Some text. + // * Some more text. + // */ + // + // is handled by replacing the whitespace sequences before the * by a single space + return \preg_replace('(^\\s+\\*)m', ' *', $this->text); + } elseif (\preg_match('(^/\\*\\*?\\s*[\\r\\n])', $text) && \preg_match('(\\n(\\s*)\\*/$)', $text, $matches)) { + // Multi line comment of the type + // + // /* + // Some text. + // Some more text. + // */ + // + // is handled by removing the whitespace sequence on the line before the closing + // */ on all lines. So if the last line is " */", then " " is removed at the + // start of all lines. + return \preg_replace('(^' . \preg_quote($matches[1]) . ')m', '', $text); + } elseif (\preg_match('(^/\\*\\*?\\s*(?!\\s))', $text, $matches)) { + // Multi line comment of the type + // + // /* Some text. + // Some more text. + // Indented text. + // Even more text. */ + // + // is handled by removing the difference between the shortest whitespace prefix on all + // lines and the length of the "/* " opening sequence. + $prefixLen = $this->getShortestWhitespacePrefixLen(\substr($text, $newlinePos + 1)); + $removeLen = $prefixLen - \strlen($matches[0]); + return \preg_replace('(^\\s{' . $removeLen . '})m', '', $text); + } + // No idea how to format this comment, so simply return as is + return $text; + } + /** + * Get length of shortest whitespace prefix (at the start of a line). + * + * If there is a line with no prefix whitespace, 0 is a valid return value. + * + * @param string $str String to check + * @return int Length in characters. Tabs count as single characters. + */ + private function getShortestWhitespacePrefixLen($str) + { + if (!\is_string($str)) { + if (!(\is_string($str) || \is_object($str) && \method_exists($str, '__toString') || (\is_bool($str) || \is_numeric($str)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($str) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($str) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $str = (string) $str; + } + } + $lines = \explode("\n", $str); + $shortestPrefixLen = \INF; + foreach ($lines as $line) { + \preg_match('(^\\s*)', $line, $matches); + $prefixLen = \strlen($matches[0]); + if ($prefixLen < $shortestPrefixLen) { + $shortestPrefixLen = $prefixLen; + } + } + $phabelReturn = $shortestPrefixLen; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return array + * @psalm-return array{nodeType:string, text:mixed, line:mixed, filePos:mixed} + */ + public function jsonSerialize() + { + // Technically not a node, but we make it look like one anyway + $type = $this instanceof Comment\Doc ? 'Comment_Doc' : 'Comment'; + $phabelReturn = [ + 'nodeType' => $type, + 'text' => $this->text, + // TODO: Rename these to include "start". + 'line' => $this->startLine, + 'filePos' => $this->startFilePos, + 'tokenPos' => $this->startTokenPos, + 'endLine' => $this->endLine, + 'endFilePos' => $this->endFilePos, + 'endTokenPos' => $this->endTokenPos, + ]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Comment/Doc.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Comment/Doc.php new file mode 100644 index 000000000..d4d399f16 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Comment/Doc.php @@ -0,0 +1,7 @@ +fallbackEvaluator = isset($fallbackEvaluator) ? $fallbackEvaluator : function (Expr $expr) { + throw new ConstExprEvaluationException("Expression of type {$expr->getType()} cannot be evaluated"); + }; + } + /** + * Silently evaluates a constant expression into a PHP value. + * + * Thrown Errors, warnings or notices will be converted into a ConstExprEvaluationException. + * The original source of the exception is available through getPrevious(). + * + * If some part of the expression cannot be evaluated, the fallback evaluator passed to the + * constructor will be invoked. By default, if no fallback is provided, an exception of type + * ConstExprEvaluationException is thrown. + * + * See class doc comment for caveats and limitations. + * + * @param Expr $expr Constant expression to evaluate + * @return mixed Result of evaluation + * + * @throws ConstExprEvaluationException if the expression cannot be evaluated or an error occurred + */ + public function evaluateSilently(Expr $expr) + { + \set_error_handler(function ($num, $str, $file, $line) { + throw new \ErrorException($str, 0, $num, $file, $line); + }); + try { + return $this->evaluate($expr); + } catch (\Exception $e) { + if (!$e instanceof ConstExprEvaluationException) { + $e = new ConstExprEvaluationException("An error occurred during constant expression evaluation", 0, $e); + } + throw $e; + } catch (\Error $e) { + if (!$e instanceof ConstExprEvaluationException) { + $e = new ConstExprEvaluationException("An error occurred during constant expression evaluation", 0, $e); + } + throw $e; + } finally { + \restore_error_handler(); + } + } + /** + * Directly evaluates a constant expression into a PHP value. + * + * May generate Error exceptions, warnings or notices. Use evaluateSilently() to convert these + * into a ConstExprEvaluationException. + * + * If some part of the expression cannot be evaluated, the fallback evaluator passed to the + * constructor will be invoked. By default, if no fallback is provided, an exception of type + * ConstExprEvaluationException is thrown. + * + * See class doc comment for caveats and limitations. + * + * @param Expr $expr Constant expression to evaluate + * @return mixed Result of evaluation + * + * @throws ConstExprEvaluationException if the expression cannot be evaluated + */ + public function evaluateDirectly(Expr $expr) + { + return $this->evaluate($expr); + } + private function evaluate(Expr $expr) + { + if ($expr instanceof Scalar\LNumber || $expr instanceof Scalar\DNumber || $expr instanceof Scalar\String_) { + return $expr->value; + } + if ($expr instanceof Expr\Array_) { + return $this->evaluateArray($expr); + } + // Unary operators + if ($expr instanceof Expr\UnaryPlus) { + return +$this->evaluate($expr->expr); + } + if ($expr instanceof Expr\UnaryMinus) { + return -$this->evaluate($expr->expr); + } + if ($expr instanceof Expr\BooleanNot) { + return !$this->evaluate($expr->expr); + } + if ($expr instanceof Expr\BitwiseNot) { + return ~$this->evaluate($expr->expr); + } + if ($expr instanceof Expr\BinaryOp) { + return $this->evaluateBinaryOp($expr); + } + if ($expr instanceof Expr\Ternary) { + return $this->evaluateTernary($expr); + } + if ($expr instanceof Expr\ArrayDimFetch && null !== $expr->dim) { + return $this->evaluate($expr->var)[$this->evaluate($expr->dim)]; + } + if ($expr instanceof Expr\ConstFetch) { + return $this->evaluateConstFetch($expr); + } + $phabel_01f4a24c58cdb12a = $this->fallbackEvaluator; + return $phabel_01f4a24c58cdb12a($expr); + } + private function evaluateArray(Expr\Array_ $expr) + { + $array = []; + foreach ($expr->items as $item) { + if (null !== $item->key) { + $array[$this->evaluate($item->key)] = $this->evaluate($item->value); + } else { + $array[] = $this->evaluate($item->value); + } + } + return $array; + } + private function evaluateTernary(Expr\Ternary $expr) + { + if (null === $expr->if) { + return $this->evaluate($expr->cond) ?: $this->evaluate($expr->else); + } + return $this->evaluate($expr->cond) ? $this->evaluate($expr->if) : $this->evaluate($expr->else); + } + private function evaluateBinaryOp(Expr\BinaryOp $expr) + { + if ($expr instanceof Expr\BinaryOp\Coalesce && $expr->left instanceof Expr\ArrayDimFetch) { + // This needs to be special cased to respect BP_VAR_IS fetch semantics + return NULL !== ($phabel_fa1a6451ccff3757 = $this->evaluate($expr->left->var)) && isset($phabel_fa1a6451ccff3757[$this->evaluate($expr->left->dim)]) ? $phabel_fa1a6451ccff3757[$this->evaluate($expr->left->dim)] : $this->evaluate($expr->right); + } + // The evaluate() calls are repeated in each branch, because some of the operators are + // short-circuiting and evaluating the RHS in advance may be illegal in that case + $l = $expr->left; + $r = $expr->right; + switch ($expr->getOperatorSigil()) { + case '&': + return $this->evaluate($l) & $this->evaluate($r); + case '|': + return $this->evaluate($l) | $this->evaluate($r); + case '^': + return $this->evaluate($l) ^ $this->evaluate($r); + case '&&': + return $this->evaluate($l) && $this->evaluate($r); + case '||': + return $this->evaluate($l) || $this->evaluate($r); + case '??': + return NULL !== ($phabel_f51b4afbf89e6c35 = $this->evaluate($l)) ? $phabel_f51b4afbf89e6c35 : $this->evaluate($r); + case '.': + return $this->evaluate($l) . $this->evaluate($r); + case '/': + return $this->evaluate($l) / $this->evaluate($r); + case '==': + return $this->evaluate($l) == $this->evaluate($r); + case '>': + return $this->evaluate($l) > $this->evaluate($r); + case '>=': + return $this->evaluate($l) >= $this->evaluate($r); + case '===': + return $this->evaluate($l) === $this->evaluate($r); + case 'and': + return $this->evaluate($l) and $this->evaluate($r); + case 'or': + return $this->evaluate($l) or $this->evaluate($r); + case 'xor': + return $this->evaluate($l) xor $this->evaluate($r); + case '-': + return $this->evaluate($l) - $this->evaluate($r); + case '%': + return $this->evaluate($l) % $this->evaluate($r); + case '*': + return $this->evaluate($l) * $this->evaluate($r); + case '!=': + return $this->evaluate($l) != $this->evaluate($r); + case '!==': + return $this->evaluate($l) !== $this->evaluate($r); + case '+': + return $this->evaluate($l) + $this->evaluate($r); + case '**': + return $this->evaluate($l) ** $this->evaluate($r); + case '<<': + return $this->evaluate($l) << $this->evaluate($r); + case '>>': + return $this->evaluate($l) >> $this->evaluate($r); + case '<': + return $this->evaluate($l) < $this->evaluate($r); + case '<=': + return $this->evaluate($l) <= $this->evaluate($r); + case '<=>': + return \Phabel\Target\Php70\SpaceshipOperatorReplacer::spaceship($this->evaluate($l), $this->evaluate($r)); + } + throw new \Exception('Should not happen'); + } + private function evaluateConstFetch(Expr\ConstFetch $expr) + { + $name = $expr->name->toLowerString(); + switch ($name) { + case 'null': + return null; + case 'false': + return \false; + case 'true': + return \true; + } + $phabel_82a8347237169f2f = $this->fallbackEvaluator; + return $phabel_82a8347237169f2f($expr); + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Error.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Error.php new file mode 100644 index 000000000..6af4dfdf7 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Error.php @@ -0,0 +1,295 @@ +rawMessage = $message; + if (\is_array($attributes)) { + $this->attributes = $attributes; + } else { + $this->attributes = ['startLine' => $attributes]; + } + $this->updateMessage(); + } + /** + * Gets the error message + * + * @return string Error message + */ + public function getRawMessage() + { + $phabelReturn = $this->rawMessage; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the line the error starts in. + * + * @return int Error start line + */ + public function getStartLine() + { + $phabelReturn = isset($this->attributes['startLine']) ? $this->attributes['startLine'] : -1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the line the error ends in. + * + * @return int Error end line + */ + public function getEndLine() + { + $phabelReturn = isset($this->attributes['endLine']) ? $this->attributes['endLine'] : -1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the attributes of the node/token the error occurred at. + * + * @return array + */ + public function getAttributes() + { + $phabelReturn = $this->attributes; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Sets the attributes of the node/token the error occurred at. + * + * @param array $attributes + */ + public function setAttributes(array $attributes) + { + $this->attributes = $attributes; + $this->updateMessage(); + } + /** + * Sets the line of the PHP file the error occurred in. + * + * @param string $message Error message + */ + public function setRawMessage($message) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + $this->rawMessage = $message; + $this->updateMessage(); + } + /** + * Sets the line the error starts in. + * + * @param int $line Error start line + */ + public function setStartLine($line) + { + if (!\is_int($line)) { + if (!(\is_bool($line) || \is_numeric($line))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($line) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($line) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $line = (int) $line; + } + } + $this->attributes['startLine'] = $line; + $this->updateMessage(); + } + /** + * Returns whether the error has start and end column information. + * + * For column information enable the startFilePos and endFilePos in the lexer options. + * + * @return bool + */ + public function hasColumnInfo() + { + $phabelReturn = isset($this->attributes['startFilePos'], $this->attributes['endFilePos']); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the start column (1-based) into the line where the error started. + * + * @param string $code Source code of the file + * @return int + */ + public function getStartColumn($code) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + if (!$this->hasColumnInfo()) { + throw new \RuntimeException('Error does not have column information'); + } + $phabelReturn = $this->toColumn($code, $this->attributes['startFilePos']); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the end column (1-based) into the line where the error ended. + * + * @param string $code Source code of the file + * @return int + */ + public function getEndColumn($code) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + if (!$this->hasColumnInfo()) { + throw new \RuntimeException('Error does not have column information'); + } + $phabelReturn = $this->toColumn($code, $this->attributes['endFilePos']); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Formats message including line and column information. + * + * @param string $code Source code associated with the error, for calculation of the columns + * + * @return string Formatted message + */ + public function getMessageWithColumnInfo($code) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $phabelReturn = \sprintf('%s from %d:%d to %d:%d', $this->getRawMessage(), $this->getStartLine(), $this->getStartColumn($code), $this->getEndLine(), $this->getEndColumn($code)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Converts a file offset into a column. + * + * @param string $code Source code that $pos indexes into + * @param int $pos 0-based position in $code + * + * @return int 1-based column (relative to start of line) + */ + private function toColumn($code, $pos) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + if (!\is_int($pos)) { + if (!(\is_bool($pos) || \is_numeric($pos))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($pos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pos = (int) $pos; + } + } + if ($pos > \strlen($code)) { + throw new \RuntimeException('Invalid position information'); + } + $lineStartPos = \strrpos($code, "\n", $pos - \strlen($code)); + if (\false === $lineStartPos) { + $lineStartPos = -1; + } + $phabelReturn = $pos - $lineStartPos; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Updates the exception message after a change to rawMessage or rawLine. + */ + protected function updateMessage() + { + $this->message = $this->rawMessage; + if (-1 === $this->getStartLine()) { + $this->message .= ' on unknown line'; + } else { + $this->message .= ' on line ' . $this->getStartLine(); + } + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/ErrorHandler.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/ErrorHandler.php new file mode 100644 index 000000000..40083b886 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/ErrorHandler.php @@ -0,0 +1,13 @@ +errors[] = $error; + } + /** + * Get collected errors. + * + * @return Error[] + */ + public function getErrors() + { + $phabelReturn = $this->errors; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Check whether there are any errors. + * + * @return bool + */ + public function hasErrors() + { + $phabelReturn = !empty($this->errors); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Reset/clear collected errors. + */ + public function clearErrors() + { + $this->errors = []; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/ErrorHandler/Throwing.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/ErrorHandler/Throwing.php new file mode 100644 index 000000000..a76c38dee --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/ErrorHandler/Throwing.php @@ -0,0 +1,18 @@ +type = $type; + $this->old = $old; + $this->new = $new; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Internal/Differ.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Internal/Differ.php new file mode 100644 index 000000000..7e1570171 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Internal/Differ.php @@ -0,0 +1,171 @@ +isEqual = $isEqual; + } + /** + * Calculate diff (edit script) from $old to $new. + * + * @param array $old Original array + * @param array $new New array + * + * @return DiffElem[] Diff (edit script) + */ + public function diff(array $old, array $new) + { + list($trace, $x, $y) = $this->calculateTrace($old, $new); + return $this->extractDiff($trace, $x, $y, $old, $new); + } + /** + * Calculate diff, including "replace" operations. + * + * If a sequence of remove operations is followed by the same number of add operations, these + * will be coalesced into replace operations. + * + * @param array $old Original array + * @param array $new New array + * + * @return DiffElem[] Diff (edit script), including replace operations + */ + public function diffWithReplacements(array $old, array $new) + { + return $this->coalesceReplacements($this->diff($old, $new)); + } + private function calculateTrace(array $a, array $b) + { + $n = \count($a); + $m = \count($b); + $max = $n + $m; + $v = [1 => 0]; + $trace = []; + for ($d = 0; $d <= $max; $d++) { + $trace[] = $v; + for ($k = -$d; $k <= $d; $k += 2) { + if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { + $x = $v[$k + 1]; + } else { + $x = $v[$k - 1] + 1; + } + $y = $x - $k; + if ($x < $n && $y < $m) { + $phabel_61a83b60b2ff577d = $this->isEqual; + $phabel_02c2d1ecdbc7cd41 = (bool) $phabel_61a83b60b2ff577d($a[$x], $b[$y]); + } else { + $phabel_02c2d1ecdbc7cd41 = \false; + } + while ($phabel_02c2d1ecdbc7cd41) { + $x++; + $y++; + } + $v[$k] = $x; + if ($x >= $n && $y >= $m) { + return [$trace, $x, $y]; + } + } + } + throw new \Exception('Should not happen'); + } + private function extractDiff(array $trace, $x, $y, array $a, array $b) + { + if (!\is_int($x)) { + if (!(\is_bool($x) || \is_numeric($x))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($x) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($x) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $x = (int) $x; + } + } + if (!\is_int($y)) { + if (!(\is_bool($y) || \is_numeric($y))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($y) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($y) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $y = (int) $y; + } + } + $result = []; + for ($d = \count($trace) - 1; $d >= 0; $d--) { + $v = $trace[$d]; + $k = $x - $y; + if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { + $prevK = $k + 1; + } else { + $prevK = $k - 1; + } + $prevX = $v[$prevK]; + $prevY = $prevX - $prevK; + while ($x > $prevX && $y > $prevY) { + $result[] = new DiffElem(DiffElem::TYPE_KEEP, $a[$x - 1], $b[$y - 1]); + $x--; + $y--; + } + if ($d === 0) { + break; + } + while ($x > $prevX) { + $result[] = new DiffElem(DiffElem::TYPE_REMOVE, $a[$x - 1], null); + $x--; + } + while ($y > $prevY) { + $result[] = new DiffElem(DiffElem::TYPE_ADD, null, $b[$y - 1]); + $y--; + } + } + return \array_reverse($result); + } + /** + * Coalesce equal-length sequences of remove+add into a replace operation. + * + * @param DiffElem[] $diff + * @return DiffElem[] + */ + private function coalesceReplacements(array $diff) + { + $newDiff = []; + $c = \count($diff); + for ($i = 0; $i < $c; $i++) { + $diffType = $diff[$i]->type; + if ($diffType !== DiffElem::TYPE_REMOVE) { + $newDiff[] = $diff[$i]; + continue; + } + $j = $i; + while ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) { + $j++; + } + $k = $j; + while ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) { + $k++; + } + if ($j - $i === $k - $j) { + $len = $j - $i; + for ($n = 0; $n < $len; $n++) { + $newDiff[] = new DiffElem(DiffElem::TYPE_REPLACE, $diff[$i + $n]->old, $diff[$j + $n]->new); + } + } else { + for (; $i < $k; $i++) { + $newDiff[] = $diff[$i]; + } + } + $i = $k - 1; + } + return $newDiff; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php new file mode 100644 index 000000000..1d9fd8af1 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php @@ -0,0 +1,66 @@ +attrGroups = $attrGroups; + $this->args = $args; + $this->extends = $extends; + $this->implements = $implements; + $this->stmts = $stmts; + } + public static function fromNewNode(Expr\New_ $newNode) + { + $class = $newNode->class; + \assert($class instanceof Node\Stmt\Class_); + // We don't assert that $class->name is null here, to allow consumers to assign unique names + // to anonymous classes for their own purposes. We simplify ignore the name here. + return new self($class->attrGroups, $newNode->args, $class->extends, $class->implements, $class->stmts, $newNode->getAttributes()); + } + public function getType() + { + $phabelReturn = 'Expr_PrintableNewAnonClass'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function getSubNodeNames() + { + $phabelReturn = ['attrGroups', 'args', 'extends', 'implements', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Internal/TokenStream.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Internal/TokenStream.php new file mode 100644 index 000000000..2b2c245ba --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Internal/TokenStream.php @@ -0,0 +1,462 @@ +tokens = $tokens; + $this->indentMap = $this->calcIndentMap(); + } + /** + * Whether the given position is immediately surrounded by parenthesis. + * + * @param int $startPos Start position + * @param int $endPos End position + * + * @return bool + */ + public function haveParens($startPos, $endPos) + { + if (!\is_int($startPos)) { + if (!(\is_bool($startPos) || \is_numeric($startPos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($startPos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($startPos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $startPos = (int) $startPos; + } + } + if (!\is_int($endPos)) { + if (!(\is_bool($endPos) || \is_numeric($endPos))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($endPos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($endPos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $endPos = (int) $endPos; + } + } + $phabelReturn = $this->haveTokenImmediatelyBefore($startPos, '(') && $this->haveTokenImmediatelyAfter($endPos, ')'); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether the given position is immediately surrounded by braces. + * + * @param int $startPos Start position + * @param int $endPos End position + * + * @return bool + */ + public function haveBraces($startPos, $endPos) + { + if (!\is_int($startPos)) { + if (!(\is_bool($startPos) || \is_numeric($startPos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($startPos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($startPos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $startPos = (int) $startPos; + } + } + if (!\is_int($endPos)) { + if (!(\is_bool($endPos) || \is_numeric($endPos))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($endPos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($endPos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $endPos = (int) $endPos; + } + } + $phabelReturn = ($this->haveTokenImmediatelyBefore($startPos, '{') || $this->haveTokenImmediatelyBefore($startPos, \T_CURLY_OPEN)) && $this->haveTokenImmediatelyAfter($endPos, '}'); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Check whether the position is directly preceded by a certain token type. + * + * During this check whitespace and comments are skipped. + * + * @param int $pos Position before which the token should occur + * @param int|string $expectedTokenType Token to check for + * + * @return bool Whether the expected token was found + */ + public function haveTokenImmediatelyBefore($pos, $expectedTokenType) + { + if (!\is_int($pos)) { + if (!(\is_bool($pos) || \is_numeric($pos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($pos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pos = (int) $pos; + } + } + $tokens = $this->tokens; + $pos--; + for (; $pos >= 0; $pos--) { + $tokenType = $tokens[$pos][0]; + if ($tokenType === $expectedTokenType) { + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if ($tokenType !== \T_WHITESPACE && $tokenType !== \T_COMMENT && $tokenType !== \T_DOC_COMMENT) { + break; + } + } + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Check whether the position is directly followed by a certain token type. + * + * During this check whitespace and comments are skipped. + * + * @param int $pos Position after which the token should occur + * @param int|string $expectedTokenType Token to check for + * + * @return bool Whether the expected token was found + */ + public function haveTokenImmediatelyAfter($pos, $expectedTokenType) + { + if (!\is_int($pos)) { + if (!(\is_bool($pos) || \is_numeric($pos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($pos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pos = (int) $pos; + } + } + $tokens = $this->tokens; + $pos++; + for (; $pos < \count($tokens); $pos++) { + $tokenType = $tokens[$pos][0]; + if ($tokenType === $expectedTokenType) { + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if ($tokenType !== \T_WHITESPACE && $tokenType !== \T_COMMENT && $tokenType !== \T_DOC_COMMENT) { + break; + } + } + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function skipLeft($pos, $skipTokenType) + { + if (!\is_int($pos)) { + if (!(\is_bool($pos) || \is_numeric($pos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($pos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pos = (int) $pos; + } + } + $tokens = $this->tokens; + $pos = $this->skipLeftWhitespace($pos); + if ($skipTokenType === \T_WHITESPACE) { + return $pos; + } + if ($tokens[$pos][0] !== $skipTokenType) { + // Shouldn't happen. The skip token MUST be there + throw new \Exception('Encountered unexpected token'); + } + $pos--; + return $this->skipLeftWhitespace($pos); + } + public function skipRight($pos, $skipTokenType) + { + if (!\is_int($pos)) { + if (!(\is_bool($pos) || \is_numeric($pos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($pos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pos = (int) $pos; + } + } + $tokens = $this->tokens; + $pos = $this->skipRightWhitespace($pos); + if ($skipTokenType === \T_WHITESPACE) { + return $pos; + } + if ($tokens[$pos][0] !== $skipTokenType) { + // Shouldn't happen. The skip token MUST be there + throw new \Exception('Encountered unexpected token'); + } + $pos++; + return $this->skipRightWhitespace($pos); + } + /** + * Return first non-whitespace token position smaller or equal to passed position. + * + * @param int $pos Token position + * @return int Non-whitespace token position + */ + public function skipLeftWhitespace($pos) + { + if (!\is_int($pos)) { + if (!(\is_bool($pos) || \is_numeric($pos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($pos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pos = (int) $pos; + } + } + $tokens = $this->tokens; + for (; $pos >= 0; $pos--) { + $type = $tokens[$pos][0]; + if ($type !== \T_WHITESPACE && $type !== \T_COMMENT && $type !== \T_DOC_COMMENT) { + break; + } + } + return $pos; + } + /** + * Return first non-whitespace position greater or equal to passed position. + * + * @param int $pos Token position + * @return int Non-whitespace token position + */ + public function skipRightWhitespace($pos) + { + if (!\is_int($pos)) { + if (!(\is_bool($pos) || \is_numeric($pos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($pos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pos = (int) $pos; + } + } + $tokens = $this->tokens; + for ($count = \count($tokens); $pos < $count; $pos++) { + $type = $tokens[$pos][0]; + if ($type !== \T_WHITESPACE && $type !== \T_COMMENT && $type !== \T_DOC_COMMENT) { + break; + } + } + return $pos; + } + public function findRight($pos, $findTokenType) + { + if (!\is_int($pos)) { + if (!(\is_bool($pos) || \is_numeric($pos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($pos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pos = (int) $pos; + } + } + $tokens = $this->tokens; + for ($count = \count($tokens); $pos < $count; $pos++) { + $type = $tokens[$pos][0]; + if ($type === $findTokenType) { + return $pos; + } + } + return -1; + } + /** + * Whether the given position range contains a certain token type. + * + * @param int $startPos Starting position (inclusive) + * @param int $endPos Ending position (exclusive) + * @param int|string $tokenType Token type to look for + * @return bool Whether the token occurs in the given range + */ + public function haveTokenInRange($startPos, $endPos, $tokenType) + { + if (!\is_int($startPos)) { + if (!(\is_bool($startPos) || \is_numeric($startPos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($startPos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($startPos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $startPos = (int) $startPos; + } + } + if (!\is_int($endPos)) { + if (!(\is_bool($endPos) || \is_numeric($endPos))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($endPos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($endPos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $endPos = (int) $endPos; + } + } + $tokens = $this->tokens; + for ($pos = $startPos; $pos < $endPos; $pos++) { + if ($tokens[$pos][0] === $tokenType) { + return \true; + } + } + return \false; + } + public function haveBracesInRange($startPos, $endPos) + { + if (!\is_int($startPos)) { + if (!(\is_bool($startPos) || \is_numeric($startPos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($startPos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($startPos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $startPos = (int) $startPos; + } + } + if (!\is_int($endPos)) { + if (!(\is_bool($endPos) || \is_numeric($endPos))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($endPos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($endPos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $endPos = (int) $endPos; + } + } + return $this->haveTokenInRange($startPos, $endPos, '{') || $this->haveTokenInRange($startPos, $endPos, \T_CURLY_OPEN) || $this->haveTokenInRange($startPos, $endPos, '}'); + } + /** + * Get indentation before token position. + * + * @param int $pos Token position + * + * @return int Indentation depth (in spaces) + */ + public function getIndentationBefore($pos) + { + if (!\is_int($pos)) { + if (!(\is_bool($pos) || \is_numeric($pos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($pos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pos = (int) $pos; + } + } + $phabelReturn = $this->indentMap[$pos]; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Get the code corresponding to a token offset range, optionally adjusted for indentation. + * + * @param int $from Token start position (inclusive) + * @param int $to Token end position (exclusive) + * @param int $indent By how much the code should be indented (can be negative as well) + * + * @return string Code corresponding to token range, adjusted for indentation + */ + public function getTokenCode($from, $to, $indent) + { + if (!\is_int($from)) { + if (!(\is_bool($from) || \is_numeric($from))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($from) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($from) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $from = (int) $from; + } + } + if (!\is_int($to)) { + if (!(\is_bool($to) || \is_numeric($to))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($to) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($to) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $to = (int) $to; + } + } + if (!\is_int($indent)) { + if (!(\is_bool($indent) || \is_numeric($indent))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($indent) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($indent) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $indent = (int) $indent; + } + } + $tokens = $this->tokens; + $result = ''; + for ($pos = $from; $pos < $to; $pos++) { + $token = $tokens[$pos]; + if (\is_array($token)) { + $type = $token[0]; + $content = $token[1]; + if ($type === \T_CONSTANT_ENCAPSED_STRING || $type === \T_ENCAPSED_AND_WHITESPACE) { + $result .= $content; + } else { + // TODO Handle non-space indentation + if ($indent < 0) { + $result .= \str_replace("\n" . \str_repeat(" ", -$indent), "\n", $content); + } elseif ($indent > 0) { + $result .= \str_replace("\n", "\n" . \str_repeat(" ", $indent), $content); + } else { + $result .= $content; + } + } + } else { + $result .= $token; + } + } + $phabelReturn = $result; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Precalculate the indentation at every token position. + * + * @return int[] Token position to indentation map + */ + private function calcIndentMap() + { + $indentMap = []; + $indent = 0; + foreach ($this->tokens as $token) { + $indentMap[] = $indent; + if ($token[0] === \T_WHITESPACE) { + $content = $token[1]; + $newlinePos = \strrpos($content, "\n"); + if (\false !== $newlinePos) { + $indent = \strlen($content) - $newlinePos - 1; + } + } + } + // Add a sentinel for one past end of the file + $indentMap[] = $indent; + return $indentMap; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/JsonDecoder.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/JsonDecoder.php new file mode 100644 index 000000000..fabe94f0e --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/JsonDecoder.php @@ -0,0 +1,143 @@ +decodeRecursive($value); + } + private function decodeRecursive($value) + { + if (\is_array($value)) { + if (isset($value['nodeType'])) { + if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc') { + return $this->decodeComment($value); + } + return $this->decodeNode($value); + } + return $this->decodeArray($value); + } + return $value; + } + private function decodeArray(array $array) + { + $decodedArray = []; + foreach ($array as $key => $value) { + $decodedArray[$key] = $this->decodeRecursive($value); + } + $phabelReturn = $decodedArray; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function decodeNode(array $value) + { + $nodeType = $value['nodeType']; + if (!\is_string($nodeType)) { + throw new \RuntimeException('Node type must be a string'); + } + $reflectionClass = $this->reflectionClassFromNodeType($nodeType); + /** @var Node $node */ + $node = $reflectionClass->newInstanceWithoutConstructor(); + if (isset($value['attributes'])) { + if (!\is_array($value['attributes'])) { + throw new \RuntimeException('Attributes must be an array'); + } + $node->setAttributes($this->decodeArray($value['attributes'])); + } + foreach ($value as $name => $subNode) { + if ($name === 'nodeType' || $name === 'attributes') { + continue; + } + $node->{$name} = $this->decodeRecursive($subNode); + } + $phabelReturn = $node; + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function decodeComment(array $value) + { + $className = $value['nodeType'] === 'Comment' ? Comment::class : Comment\Doc::class; + if (!isset($value['text'])) { + throw new \RuntimeException('Comment must have text'); + } + $phabelReturn = new $className($value['text'], isset($value['line']) ? $value['line'] : -1, isset($value['filePos']) ? $value['filePos'] : -1, isset($value['tokenPos']) ? $value['tokenPos'] : -1, isset($value['endLine']) ? $value['endLine'] : -1, isset($value['endFilePos']) ? $value['endFilePos'] : -1, isset($value['endTokenPos']) ? $value['endTokenPos'] : -1); + if (!$phabelReturn instanceof Comment) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Comment, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function reflectionClassFromNodeType($nodeType) + { + if (!\is_string($nodeType)) { + if (!(\is_string($nodeType) || \is_object($nodeType) && \method_exists($nodeType, '__toString') || (\is_bool($nodeType) || \is_numeric($nodeType)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($nodeType) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($nodeType) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $nodeType = (string) $nodeType; + } + } + if (!isset($this->reflectionClassCache[$nodeType])) { + $className = $this->classNameFromNodeType($nodeType); + $this->reflectionClassCache[$nodeType] = new \ReflectionClass($className); + } + $phabelReturn = $this->reflectionClassCache[$nodeType]; + if (!$phabelReturn instanceof \ReflectionClass) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ReflectionClass, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function classNameFromNodeType($nodeType) + { + if (!\is_string($nodeType)) { + if (!(\is_string($nodeType) || \is_object($nodeType) && \method_exists($nodeType, '__toString') || (\is_bool($nodeType) || \is_numeric($nodeType)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($nodeType) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($nodeType) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $nodeType = (string) $nodeType; + } + } + $className = 'PhpParser\\Node\\' . \strtr($nodeType, '_', '\\'); + if (\class_exists($className)) { + $phabelReturn = $className; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $className .= '_'; + if (\class_exists($className)) { + $phabelReturn = $className; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + throw new \RuntimeException("Unknown node type \"{$nodeType}\""); + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer.php new file mode 100644 index 000000000..93a25c0ad --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer.php @@ -0,0 +1,490 @@ +defineCompatibilityTokens(); + $this->tokenMap = $this->createTokenMap(); + $this->identifierTokens = $this->createIdentifierTokenMap(); + // map of tokens to drop while lexing (the map is only used for isset lookup, + // that's why the value is simply set to 1; the value is never actually used.) + $this->dropTokens = \array_fill_keys([\T_WHITESPACE, \T_OPEN_TAG, \T_COMMENT, \T_DOC_COMMENT, \T_BAD_CHARACTER], 1); + $defaultAttributes = ['comments', 'startLine', 'endLine']; + $usedAttributes = \array_fill_keys(isset($options['usedAttributes']) ? $options['usedAttributes'] : $defaultAttributes, \true); + // Create individual boolean properties to make these checks faster. + $this->attributeStartLineUsed = isset($usedAttributes['startLine']); + $this->attributeEndLineUsed = isset($usedAttributes['endLine']); + $this->attributeStartTokenPosUsed = isset($usedAttributes['startTokenPos']); + $this->attributeEndTokenPosUsed = isset($usedAttributes['endTokenPos']); + $this->attributeStartFilePosUsed = isset($usedAttributes['startFilePos']); + $this->attributeEndFilePosUsed = isset($usedAttributes['endFilePos']); + $this->attributeCommentsUsed = isset($usedAttributes['comments']); + } + /** + * Initializes the lexer for lexing the provided source code. + * + * This function does not throw if lexing errors occur. Instead, errors may be retrieved using + * the getErrors() method. + * + * @param string $code The source code to lex + * @param ErrorHandler|null $errorHandler Error handler to use for lexing errors. Defaults to + * ErrorHandler\Throwing + */ + public function startLexing($code, ErrorHandler $errorHandler = null) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + if (null === $errorHandler) { + $errorHandler = new ErrorHandler\Throwing(); + } + $this->code = $code; + // keep the code around for __halt_compiler() handling + $this->pos = -1; + $this->line = 1; + $this->filePos = 0; + // If inline HTML occurs without preceding code, treat it as if it had a leading newline. + // This ensures proper composability, because having a newline is the "safe" assumption. + $this->prevCloseTagHasNewline = \true; + $scream = \ini_set('xdebug.scream', '0'); + $this->tokens = @\token_get_all($code); + $this->postprocessTokens($errorHandler); + if (\false !== $scream) { + \ini_set('xdebug.scream', $scream); + } + } + private function handleInvalidCharacterRange($start, $end, $line, ErrorHandler $errorHandler) + { + $tokens = []; + for ($i = $start; $i < $end; $i++) { + $chr = $this->code[$i]; + if ($chr === "\x00") { + // PHP cuts error message after null byte, so need special case + $errorMsg = 'Unexpected null byte'; + } else { + $errorMsg = \sprintf('Unexpected character "%s" (ASCII %d)', $chr, \ord($chr)); + } + $tokens[] = [\T_BAD_CHARACTER, $chr, $line]; + $errorHandler->handleError(new Error($errorMsg, ['startLine' => $line, 'endLine' => $line, 'startFilePos' => $i, 'endFilePos' => $i])); + } + return $tokens; + } + /** + * Check whether comment token is unterminated. + * + * @return bool + */ + private function isUnterminatedComment($token) + { + $phabelReturn = ($token[0] === \T_COMMENT || $token[0] === \T_DOC_COMMENT) && \substr($token[1], 0, 2) === '/*' && \substr($token[1], -2) !== '*/'; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + protected function postprocessTokens(ErrorHandler $errorHandler) + { + // PHP's error handling for token_get_all() is rather bad, so if we want detailed + // error information we need to compute it ourselves. Invalid character errors are + // detected by finding "gaps" in the token array. Unterminated comments are detected + // by checking if a trailing comment has a "*/" at the end. + // + // Additionally, we canonicalize to the PHP 8 comment format here, which does not include + // the trailing whitespace anymore. + // + // We also canonicalize to the PHP 8 T_NAME_* tokens. + $filePos = 0; + $line = 1; + $numTokens = \count($this->tokens); + for ($i = 0; $i < $numTokens; $i++) { + $token = $this->tokens[$i]; + // Since PHP 7.4 invalid characters are represented by a T_BAD_CHARACTER token. + // In this case we only need to emit an error. + if ($token[0] === \T_BAD_CHARACTER) { + $this->handleInvalidCharacterRange($filePos, $filePos + 1, $line, $errorHandler); + } + if ($token[0] === \T_COMMENT && \substr($token[1], 0, 2) !== '/*' && \preg_match('/(\\r\\n|\\n|\\r)$/D', $token[1], $matches)) { + $trailingNewline = $matches[0]; + $token[1] = \substr($token[1], 0, -\strlen($trailingNewline)); + $this->tokens[$i] = $token; + if (isset($this->tokens[$i + 1]) && $this->tokens[$i + 1][0] === \T_WHITESPACE) { + // Move trailing newline into following T_WHITESPACE token, if it already exists. + $this->tokens[$i + 1][1] = $trailingNewline . $this->tokens[$i + 1][1]; + $this->tokens[$i + 1][2]--; + } else { + // Otherwise, we need to create a new T_WHITESPACE token. + \array_splice($this->tokens, $i + 1, 0, [[\T_WHITESPACE, $trailingNewline, $line]]); + $numTokens++; + } + } + // Emulate PHP 8 T_NAME_* tokens, by combining sequences of T_NS_SEPARATOR and T_STRING + // into a single token. + if (\is_array($token) && ($token[0] === \T_NS_SEPARATOR || isset($this->identifierTokens[$token[0]]))) { + $lastWasSeparator = $token[0] === \T_NS_SEPARATOR; + $text = $token[1]; + for ($j = $i + 1; isset($this->tokens[$j]); $j++) { + if ($lastWasSeparator) { + if (!isset($this->identifierTokens[$this->tokens[$j][0]])) { + break; + } + $lastWasSeparator = \false; + } else { + if ($this->tokens[$j][0] !== \T_NS_SEPARATOR) { + break; + } + $lastWasSeparator = \true; + } + $text .= $this->tokens[$j][1]; + } + if ($lastWasSeparator) { + // Trailing separator is not part of the name. + $j--; + $text = \substr($text, 0, -1); + } + if ($j > $i + 1) { + if ($token[0] === \T_NS_SEPARATOR) { + $type = \T_NAME_FULLY_QUALIFIED; + } else { + if ($token[0] === \T_NAMESPACE) { + $type = \T_NAME_RELATIVE; + } else { + $type = \T_NAME_QUALIFIED; + } + } + $token = [$type, $text, $line]; + \array_splice($this->tokens, $i, $j - $i, [$token]); + $numTokens -= $j - $i - 1; + } + } + $tokenValue = \is_string($token) ? $token : $token[1]; + $tokenLen = \strlen($tokenValue); + if (\substr($this->code, $filePos, $tokenLen) !== $tokenValue) { + // Something is missing, must be an invalid character + $nextFilePos = \strpos($this->code, $tokenValue, $filePos); + $badCharTokens = $this->handleInvalidCharacterRange($filePos, $nextFilePos, $line, $errorHandler); + $filePos = (int) $nextFilePos; + \array_splice($this->tokens, $i, 0, $badCharTokens); + $numTokens += \count($badCharTokens); + $i += \count($badCharTokens); + } + $filePos += $tokenLen; + $line += \substr_count($tokenValue, "\n"); + } + if ($filePos !== \strlen($this->code)) { + if (\substr($this->code, $filePos, 2) === '/*') { + // Unlike PHP, HHVM will drop unterminated comments entirely + $comment = \substr($this->code, $filePos); + $errorHandler->handleError(new Error('Unterminated comment', ['startLine' => $line, 'endLine' => $line + \substr_count($comment, "\n"), 'startFilePos' => $filePos, 'endFilePos' => $filePos + \strlen($comment)])); + // Emulate the PHP behavior + $isDocComment = isset($comment[3]) && $comment[3] === '*'; + $this->tokens[] = [$isDocComment ? \T_DOC_COMMENT : \T_COMMENT, $comment, $line]; + } else { + // Invalid characters at the end of the input + $badCharTokens = $this->handleInvalidCharacterRange($filePos, \strlen($this->code), $line, $errorHandler); + $this->tokens = \array_merge($this->tokens, $badCharTokens); + } + return; + } + if (\count($this->tokens) > 0) { + // Check for unterminated comment + $lastToken = $this->tokens[\count($this->tokens) - 1]; + if ($this->isUnterminatedComment($lastToken)) { + $errorHandler->handleError(new Error('Unterminated comment', ['startLine' => $line - \substr_count($lastToken[1], "\n"), 'endLine' => $line, 'startFilePos' => $filePos - \strlen($lastToken[1]), 'endFilePos' => $filePos])); + } + } + } + /** + * Fetches the next token. + * + * The available attributes are determined by the 'usedAttributes' option, which can + * be specified in the constructor. The following attributes are supported: + * + * * 'comments' => Array of PhpParser\Comment or PhpParser\Comment\Doc instances, + * representing all comments that occurred between the previous + * non-discarded token and the current one. + * * 'startLine' => Line in which the node starts. + * * 'endLine' => Line in which the node ends. + * * 'startTokenPos' => Offset into the token array of the first token in the node. + * * 'endTokenPos' => Offset into the token array of the last token in the node. + * * 'startFilePos' => Offset into the code string of the first character that is part of the node. + * * 'endFilePos' => Offset into the code string of the last character that is part of the node. + * + * @param mixed $value Variable to store token content in + * @param mixed $startAttributes Variable to store start attributes in + * @param mixed $endAttributes Variable to store end attributes in + * + * @return int Token id + */ + public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) + { + $startAttributes = []; + $endAttributes = []; + while (1) { + if (isset($this->tokens[++$this->pos])) { + $token = $this->tokens[$this->pos]; + } else { + // EOF token with ID 0 + $token = "\x00"; + } + if ($this->attributeStartLineUsed) { + $startAttributes['startLine'] = $this->line; + } + if ($this->attributeStartTokenPosUsed) { + $startAttributes['startTokenPos'] = $this->pos; + } + if ($this->attributeStartFilePosUsed) { + $startAttributes['startFilePos'] = $this->filePos; + } + if (\is_string($token)) { + $value = $token; + if (isset($token[1])) { + // bug in token_get_all + $this->filePos += 2; + $id = \ord('"'); + } else { + $this->filePos += 1; + $id = \ord($token); + } + } elseif (!isset($this->dropTokens[$token[0]])) { + $value = $token[1]; + $id = $this->tokenMap[$token[0]]; + if (\T_CLOSE_TAG === $token[0]) { + $this->prevCloseTagHasNewline = \false !== \strpos($token[1], "\n"); + } elseif (\T_INLINE_HTML === $token[0]) { + $startAttributes['hasLeadingNewline'] = $this->prevCloseTagHasNewline; + } + $this->line += \substr_count($value, "\n"); + $this->filePos += \strlen($value); + } else { + $origLine = $this->line; + $origFilePos = $this->filePos; + $this->line += \substr_count($token[1], "\n"); + $this->filePos += \strlen($token[1]); + if (\T_COMMENT === $token[0] || \T_DOC_COMMENT === $token[0]) { + if ($this->attributeCommentsUsed) { + $comment = \T_DOC_COMMENT === $token[0] ? new Comment\Doc($token[1], $origLine, $origFilePos, $this->pos, $this->line, $this->filePos - 1, $this->pos) : new Comment($token[1], $origLine, $origFilePos, $this->pos, $this->line, $this->filePos - 1, $this->pos); + $startAttributes['comments'][] = $comment; + } + } + continue; + } + if ($this->attributeEndLineUsed) { + $endAttributes['endLine'] = $this->line; + } + if ($this->attributeEndTokenPosUsed) { + $endAttributes['endTokenPos'] = $this->pos; + } + if ($this->attributeEndFilePosUsed) { + $endAttributes['endFilePos'] = $this->filePos - 1; + } + $phabelReturn = $id; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + throw new \RuntimeException('Reached end of lexer loop'); + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** + * Returns the token array for current code. + * + * The token array is in the same format as provided by the + * token_get_all() function and does not discard tokens (i.e. + * whitespace and comments are included). The token position + * attributes are against this token array. + * + * @return array Array of tokens in token_get_all() format + */ + public function getTokens() + { + $phabelReturn = $this->tokens; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Handles __halt_compiler() by returning the text after it. + * + * @return string Remaining text + */ + public function handleHaltCompiler() + { + // text after T_HALT_COMPILER, still including (); + $textAfter = \substr($this->code, $this->filePos); + // ensure that it is followed by (); + // this simplifies the situation, by not allowing any comments + // in between of the tokens. + if (!\preg_match('~^\\s*\\(\\s*\\)\\s*(?:;|\\?>\\r?\\n?)~', $textAfter, $matches)) { + throw new Error('__HALT_COMPILER must be followed by "();"'); + } + // prevent the lexer from returning any further tokens + $this->pos = \count($this->tokens); + $phabelReturn = \substr($textAfter, \strlen($matches[0])); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + // return with (); removed + return $phabelReturn; + } + private function defineCompatibilityTokens() + { + static $compatTokensDefined = \false; + if ($compatTokensDefined) { + return; + } + $compatTokens = [ + // PHP 7.4 + 'T_BAD_CHARACTER', + 'T_FN', + 'T_COALESCE_EQUAL', + // PHP 8.0 + 'T_NAME_QUALIFIED', + 'T_NAME_FULLY_QUALIFIED', + 'T_NAME_RELATIVE', + 'T_MATCH', + 'T_NULLSAFE_OBJECT_OPERATOR', + 'T_ATTRIBUTE', + ]; + // PHP-Parser might be used together with another library that also emulates some or all + // of these tokens. Perform a sanity-check that all already defined tokens have been + // assigned a unique ID. + $usedTokenIds = []; + foreach ($compatTokens as $token) { + if (\defined($token)) { + $tokenId = \constant($token); + $clashingToken = isset($usedTokenIds[$tokenId]) ? $usedTokenIds[$tokenId] : null; + if ($clashingToken !== null) { + throw new \Error(\sprintf('Token %s has same ID as token %s, you may be using a library with broken token emulation', $token, $clashingToken)); + } + $usedTokenIds[$tokenId] = $token; + } + } + // Now define any tokens that have not yet been emulated. Try to assign IDs from -1 + // downwards, but skip any IDs that may already be in use. + $newTokenId = -1; + foreach ($compatTokens as $token) { + if (!\defined($token)) { + while (isset($usedTokenIds[$newTokenId])) { + $newTokenId--; + } + \define($token, $newTokenId); + $newTokenId--; + } + } + $compatTokensDefined = \true; + } + /** + * Creates the token map. + * + * The token map maps the PHP internal token identifiers + * to the identifiers used by the Parser. Additionally it + * maps T_OPEN_TAG_WITH_ECHO to T_ECHO and T_CLOSE_TAG to ';'. + * + * @return array The token map + */ + protected function createTokenMap() + { + $tokenMap = []; + // 256 is the minimum possible token number, as everything below + // it is an ASCII value + for ($i = 256; $i < 1000; ++$i) { + if (\T_DOUBLE_COLON === $i) { + // T_DOUBLE_COLON is equivalent to T_PAAMAYIM_NEKUDOTAYIM + $tokenMap[$i] = Tokens::T_PAAMAYIM_NEKUDOTAYIM; + } elseif (\T_OPEN_TAG_WITH_ECHO === $i) { + // T_OPEN_TAG_WITH_ECHO with dropped T_OPEN_TAG results in T_ECHO + $tokenMap[$i] = Tokens::T_ECHO; + } elseif (\T_CLOSE_TAG === $i) { + // T_CLOSE_TAG is equivalent to ';' + $tokenMap[$i] = \ord(';'); + } elseif ('UNKNOWN' !== ($name = \token_name($i))) { + if ('T_HASHBANG' === $name) { + // HHVM uses a special token for #! hashbang lines + $tokenMap[$i] = Tokens::T_INLINE_HTML; + } elseif (\defined($name = Tokens::class . '::' . $name)) { + // Other tokens can be mapped directly + $tokenMap[$i] = \constant($name); + } + } + } + // HHVM uses a special token for numbers that overflow to double + if (\defined('T_ONUMBER')) { + $tokenMap[\T_ONUMBER] = Tokens::T_DNUMBER; + } + // HHVM also has a separate token for the __COMPILER_HALT_OFFSET__ constant + if (\defined('T_COMPILER_HALT_OFFSET')) { + $tokenMap[\T_COMPILER_HALT_OFFSET] = Tokens::T_STRING; + } + // Assign tokens for which we define compatibility constants, as token_name() does not know them. + $tokenMap[\T_FN] = Tokens::T_FN; + $tokenMap[\T_COALESCE_EQUAL] = Tokens::T_COALESCE_EQUAL; + $tokenMap[\T_NAME_QUALIFIED] = Tokens::T_NAME_QUALIFIED; + $tokenMap[\T_NAME_FULLY_QUALIFIED] = Tokens::T_NAME_FULLY_QUALIFIED; + $tokenMap[\T_NAME_RELATIVE] = Tokens::T_NAME_RELATIVE; + $tokenMap[\T_MATCH] = Tokens::T_MATCH; + $tokenMap[\T_NULLSAFE_OBJECT_OPERATOR] = Tokens::T_NULLSAFE_OBJECT_OPERATOR; + $tokenMap[\T_ATTRIBUTE] = Tokens::T_ATTRIBUTE; + $phabelReturn = $tokenMap; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function createIdentifierTokenMap() + { + $phabelReturn = \array_fill_keys([\T_STRING, \T_STATIC, \T_ABSTRACT, \T_FINAL, \T_PRIVATE, \T_PROTECTED, \T_PUBLIC, \T_INCLUDE, \T_INCLUDE_ONCE, \T_EVAL, \T_REQUIRE, \T_REQUIRE_ONCE, \T_LOGICAL_OR, \T_LOGICAL_XOR, \T_LOGICAL_AND, \T_INSTANCEOF, \T_NEW, \T_CLONE, \T_EXIT, \T_IF, \T_ELSEIF, \T_ELSE, \T_ENDIF, \T_ECHO, \T_DO, \T_WHILE, \T_ENDWHILE, \T_FOR, \T_ENDFOR, \T_FOREACH, \T_ENDFOREACH, \T_DECLARE, \T_ENDDECLARE, \T_AS, \T_TRY, \T_CATCH, \T_FINALLY, \T_THROW, \T_USE, \T_INSTEADOF, \T_GLOBAL, \T_VAR, \T_UNSET, \T_ISSET, \T_EMPTY, \T_CONTINUE, \T_GOTO, \T_FUNCTION, \T_CONST, \T_RETURN, \T_PRINT, \T_YIELD, \T_LIST, \T_SWITCH, \T_ENDSWITCH, \T_CASE, \T_DEFAULT, \T_BREAK, \T_ARRAY, \T_CALLABLE, \T_EXTENDS, \T_IMPLEMENTS, \T_NAMESPACE, \T_TRAIT, \T_INTERFACE, \T_CLASS, \T_CLASS_C, \T_TRAIT_C, \T_FUNC_C, \T_METHOD_C, \T_LINE, \T_FILE, \T_DIR, \T_NS_C, \T_HALT_COMPILER, \T_FN, \T_MATCH], \true); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // Based on semi_reserved production. + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/Emulative.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/Emulative.php new file mode 100644 index 000000000..0dfa7bfc2 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/Emulative.php @@ -0,0 +1,240 @@ +targetPhpVersion = isset($options['phpVersion']) ? $options['phpVersion'] : Emulative::PHP_8_0; + unset($options['phpVersion']); + parent::__construct($options); + $emulators = [new FlexibleDocStringEmulator(), new FnTokenEmulator(), new MatchTokenEmulator(), new CoaleseEqualTokenEmulator(), new NumericLiteralSeparatorEmulator(), new NullsafeTokenEmulator(), new AttributeEmulator()]; + // Collect emulators that are relevant for the PHP version we're running + // and the PHP version we're targeting for emulation. + foreach ($emulators as $emulator) { + $emulatorPhpVersion = $emulator->getPhpVersion(); + if ($this->isForwardEmulationNeeded($emulatorPhpVersion)) { + $this->emulators[] = $emulator; + } else { + if ($this->isReverseEmulationNeeded($emulatorPhpVersion)) { + $this->emulators[] = new ReverseEmulator($emulator); + } + } + } + } + public function startLexing($code, ErrorHandler $errorHandler = null) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $emulators = \array_filter($this->emulators, function ($emulator) use($code) { + return $emulator->isEmulationNeeded($code); + }); + if (empty($emulators)) { + // Nothing to emulate, yay + parent::startLexing($code, $errorHandler); + return; + } + $this->patches = []; + foreach ($emulators as $emulator) { + $code = $emulator->preprocessCode($code, $this->patches); + } + $collector = new ErrorHandler\Collecting(); + parent::startLexing($code, $collector); + $this->sortPatches(); + $this->fixupTokens(); + $errors = $collector->getErrors(); + if (!empty($errors)) { + $this->fixupErrors($errors); + foreach ($errors as $error) { + $errorHandler->handleError($error); + } + } + foreach ($emulators as $emulator) { + $this->tokens = $emulator->emulate($code, $this->tokens); + } + } + private function isForwardEmulationNeeded($emulatorPhpVersion) + { + if (!\is_string($emulatorPhpVersion)) { + if (!(\is_string($emulatorPhpVersion) || \is_object($emulatorPhpVersion) && \method_exists($emulatorPhpVersion, '__toString') || (\is_bool($emulatorPhpVersion) || \is_numeric($emulatorPhpVersion)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($emulatorPhpVersion) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($emulatorPhpVersion) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $emulatorPhpVersion = (string) $emulatorPhpVersion; + } + } + $phabelReturn = \version_compare(\PHP_VERSION, $emulatorPhpVersion, '<') && \version_compare($this->targetPhpVersion, $emulatorPhpVersion, '>='); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + private function isReverseEmulationNeeded($emulatorPhpVersion) + { + if (!\is_string($emulatorPhpVersion)) { + if (!(\is_string($emulatorPhpVersion) || \is_object($emulatorPhpVersion) && \method_exists($emulatorPhpVersion, '__toString') || (\is_bool($emulatorPhpVersion) || \is_numeric($emulatorPhpVersion)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($emulatorPhpVersion) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($emulatorPhpVersion) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $emulatorPhpVersion = (string) $emulatorPhpVersion; + } + } + $phabelReturn = \version_compare(\PHP_VERSION, $emulatorPhpVersion, '>=') && \version_compare($this->targetPhpVersion, $emulatorPhpVersion, '<'); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + private function sortPatches() + { + // Patches may be contributed by different emulators. + // Make sure they are sorted by increasing patch position. + \usort($this->patches, function ($p1, $p2) { + return \Phabel\Target\Php70\SpaceshipOperatorReplacer::spaceship($p1[0], $p2[0]); + }); + } + private function fixupTokens() + { + if (\count($this->patches) === 0) { + return; + } + // Load first patch + $patchIdx = 0; + list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; + // We use a manual loop over the tokens, because we modify the array on the fly + $pos = 0; + for ($i = 0, $c = \count($this->tokens); $i < $c; $i++) { + $token = $this->tokens[$i]; + if (\is_string($token)) { + if ($patchPos === $pos) { + // Only support replacement for string tokens. + \assert($patchType === 'replace'); + $this->tokens[$i] = $patchText; + // Fetch the next patch + $patchIdx++; + if ($patchIdx >= \count($this->patches)) { + // No more patches, we're done + return; + } + list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; + } + $pos += \strlen($token); + continue; + } + $len = \strlen($token[1]); + $posDelta = 0; + while ($patchPos >= $pos && $patchPos < $pos + $len) { + $patchTextLen = \strlen($patchText); + if ($patchType === 'remove') { + if ($patchPos === $pos && $patchTextLen === $len) { + // Remove token entirely + \array_splice($this->tokens, $i, 1, []); + $i--; + $c--; + } else { + // Remove from token string + $this->tokens[$i][1] = \substr_replace($token[1], '', $patchPos - $pos + $posDelta, $patchTextLen); + $posDelta -= $patchTextLen; + } + } elseif ($patchType === 'add') { + // Insert into the token string + $this->tokens[$i][1] = \substr_replace($token[1], $patchText, $patchPos - $pos + $posDelta, 0); + $posDelta += $patchTextLen; + } else { + if ($patchType === 'replace') { + // Replace inside the token string + $this->tokens[$i][1] = \substr_replace($token[1], $patchText, $patchPos - $pos + $posDelta, $patchTextLen); + } else { + \assert(\false); + } + } + // Fetch the next patch + $patchIdx++; + if ($patchIdx >= \count($this->patches)) { + // No more patches, we're done + return; + } + list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; + // Multiple patches may apply to the same token. Reload the current one to check + // If the new patch applies + $token = $this->tokens[$i]; + } + $pos += $len; + } + // A patch did not apply + \assert(\false); + } + /** + * Fixup line and position information in errors. + * + * @param Error[] $errors + */ + private function fixupErrors(array $errors) + { + foreach ($errors as $error) { + $attrs = $error->getAttributes(); + $posDelta = 0; + $lineDelta = 0; + foreach ($this->patches as $patch) { + list($patchPos, $patchType, $patchText) = $patch; + if ($patchPos >= $attrs['startFilePos']) { + // No longer relevant + break; + } + if ($patchType === 'add') { + $posDelta += \strlen($patchText); + $lineDelta += \substr_count($patchText, "\n"); + } else { + if ($patchType === 'remove') { + $posDelta -= \strlen($patchText); + $lineDelta -= \substr_count($patchText, "\n"); + } + } + } + $attrs['startFilePos'] += $posDelta; + $attrs['endFilePos'] += $posDelta; + $attrs['startLine'] += $lineDelta; + $attrs['endLine'] += $lineDelta; + $error->setAttributes($attrs); + } + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php new file mode 100644 index 000000000..7ad393f1a --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php @@ -0,0 +1,109 @@ +\h*)\2(?![a-zA-Z0-9_\x80-\xff])(?(?:;?[\r\n])?)/x +REGEX; + public function getPhpVersion() + { + $phabelReturn = Emulative::PHP_7_3; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function isEmulationNeeded($code) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $phabelReturn = \strpos($code, '<<<') !== \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function emulate($code, array $tokens) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $phabelReturn = $tokens; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // Handled by preprocessing + fixup. + return $phabelReturn; + } + public function reverseEmulate($code, array $tokens) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $phabelReturn = $tokens; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // Not supported. + return $phabelReturn; + } + public function preprocessCode($code, array &$patches) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + if (!\preg_match_all(self::FLEXIBLE_DOC_STRING_REGEX, $code, $matches, \PREG_SET_ORDER | \PREG_OFFSET_CAPTURE)) { + $phabelReturn = $code; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + // No heredoc/nowdoc found + return $phabelReturn; + } + // Keep track of how much we need to adjust string offsets due to the modifications we + // already made + $posDelta = 0; + foreach ($matches as $match) { + $indentation = $match['indentation'][0]; + $indentationStart = $match['indentation'][1]; + $separator = $match['separator'][0]; + $separatorStart = $match['separator'][1]; + if ($indentation === '' && $separator !== '') { + // Ordinary heredoc/nowdoc + continue; + } + if ($indentation !== '') { + // Remove indentation + $indentationLen = \strlen($indentation); + $code = \substr_replace($code, '', $indentationStart + $posDelta, $indentationLen); + $patches[] = [$indentationStart + $posDelta, 'add', $indentation]; + $posDelta -= $indentationLen; + } + if ($separator === '') { + // Insert newline as separator + $code = \substr_replace($code, "\n", $separatorStart + $posDelta, 0); + $patches[] = [$separatorStart + $posDelta, 'remove', "\n"]; + $posDelta += 1; + } + } + $phabelReturn = $code; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php new file mode 100644 index 000000000..1f485e9ed --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php @@ -0,0 +1,44 @@ +getKeywordString()) !== \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function emulate($code, array $tokens) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $keywordString = $this->getKeywordString(); + foreach ($tokens as $i => $token) { + if ($token[0] === \T_STRING && \strtolower($token[1]) === $keywordString) { + $previousNonSpaceToken = $this->getPreviousNonSpaceToken($tokens, $i); + if ($previousNonSpaceToken !== null && $previousNonSpaceToken[0] === \T_OBJECT_OPERATOR) { + continue; + } + $tokens[$i][0] = $this->getKeywordToken(); + } + } + $phabelReturn = $tokens; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param mixed[] $tokens + * @return mixed[]|null + */ + private function getPreviousNonSpaceToken(array $tokens, $start) + { + if (!\is_int($start)) { + if (!(\is_bool($start) || \is_numeric($start))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($start) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($start) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $start = (int) $start; + } + } + for ($i = $start - 1; $i >= 0; --$i) { + if ($tokens[$i][0] === \T_WHITESPACE) { + continue; + } + return $tokens[$i]; + } + return null; + } + public function reverseEmulate($code, array $tokens) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $keywordToken = $this->getKeywordToken(); + foreach ($tokens as $i => $token) { + if ($token[0] === $keywordToken) { + $tokens[$i][0] = \T_STRING; + } + } + $phabelReturn = $tokens; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php new file mode 100644 index 000000000..68258cb60 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php @@ -0,0 +1,44 @@ +') !== \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function emulate($code, array $tokens) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + // We need to manually iterate and manage a count because we'll change + // the tokens array on the way + $line = 1; + for ($i = 0, $c = \count($tokens); $i < $c; ++$i) { + if ($tokens[$i] === '?' && isset($tokens[$i + 1]) && $tokens[$i + 1][0] === \T_OBJECT_OPERATOR) { + \array_splice($tokens, $i, 2, [[\T_NULLSAFE_OBJECT_OPERATOR, '?->', $line]]); + $c--; + continue; + } + // Handle ?-> inside encapsed string. + if ($tokens[$i][0] === \T_ENCAPSED_AND_WHITESPACE && isset($tokens[$i - 1]) && $tokens[$i - 1][0] === \T_VARIABLE && \preg_match('/^\\?->([a-zA-Z_\\x80-\\xff][a-zA-Z0-9_\\x80-\\xff]*)/', $tokens[$i][1], $matches)) { + $replacement = [[\T_NULLSAFE_OBJECT_OPERATOR, '?->', $line], [\T_STRING, $matches[1], $line]]; + if (\strlen($matches[0]) !== \strlen($tokens[$i][1])) { + $replacement[] = [\T_ENCAPSED_AND_WHITESPACE, \substr($tokens[$i][1], \strlen($matches[0])), $line]; + } + \array_splice($tokens, $i, 1, $replacement); + $c += \count($replacement) - 1; + continue; + } + if (\is_array($tokens[$i])) { + $line += \substr_count($tokens[$i][1], "\n"); + } + } + $phabelReturn = $tokens; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function reverseEmulate($code, array $tokens) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $phabelReturn = $tokens; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // ?-> was not valid code previously, don't bother. + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php new file mode 100644 index 000000000..c358288eb --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php @@ -0,0 +1,147 @@ +resolveIntegerOrFloatToken($match); + $newTokens = [[$tokenKind, $match, $token[2]]]; + $numTokens = 1; + $len = $tokenLen; + while ($matchLen > $len) { + $nextToken = $tokens[$i + $numTokens]; + $nextTokenText = \is_array($nextToken) ? $nextToken[1] : $nextToken; + $nextTokenLen = \strlen($nextTokenText); + $numTokens++; + if ($matchLen < $len + $nextTokenLen) { + // Split trailing characters into a partial token. + \assert(\is_array($nextToken), "Partial token should be an array token"); + $partialText = \substr($nextTokenText, $matchLen - $len); + $newTokens[] = [$nextToken[0], $partialText, $nextToken[2]]; + break; + } + $len += $nextTokenLen; + } + \array_splice($tokens, $i, $numTokens, $newTokens); + $c -= $numTokens - \count($newTokens); + $codeOffset += $matchLen; + } + $phabelReturn = $tokens; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function resolveIntegerOrFloatToken($str) + { + if (!\is_string($str)) { + if (!(\is_string($str) || \is_object($str) && \method_exists($str, '__toString') || (\is_bool($str) || \is_numeric($str)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($str) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($str) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $str = (string) $str; + } + } + $str = \str_replace('_', '', $str); + if (\stripos($str, '0b') === 0) { + $num = \bindec($str); + } elseif (\stripos($str, '0x') === 0) { + $num = \hexdec($str); + } elseif (\stripos($str, '0') === 0 && \ctype_digit($str)) { + $num = \octdec($str); + } else { + $num = +$str; + } + $phabelReturn = \is_float($num) ? \T_DNUMBER : \T_LNUMBER; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + public function reverseEmulate($code, array $tokens) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $phabelReturn = $tokens; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // Numeric separators were not legal code previously, don't bother. + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php new file mode 100644 index 000000000..68589b72f --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php @@ -0,0 +1,96 @@ +emulator = $emulator; + } + public function getPhpVersion() + { + $phabelReturn = $this->emulator->getPhpVersion(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function isEmulationNeeded($code) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $phabelReturn = $this->emulator->isEmulationNeeded($code); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function emulate($code, array $tokens) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $phabelReturn = $this->emulator->reverseEmulate($code, $tokens); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function reverseEmulate($code, array $tokens) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $phabelReturn = $this->emulator->emulate($code, $tokens); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function preprocessCode($code, array &$patches) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $phabelReturn = $code; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php new file mode 100644 index 000000000..b1a1652dc --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php @@ -0,0 +1,37 @@ + [aliasName => originalName]] */ + protected $aliases = []; + /** @var Name[][] Same as $aliases but preserving original case */ + protected $origAliases = []; + /** @var ErrorHandler Error handler */ + protected $errorHandler; + /** + * Create a name context. + * + * @param ErrorHandler $errorHandler Error handling used to report errors + */ + public function __construct(ErrorHandler $errorHandler) + { + $this->errorHandler = $errorHandler; + } + /** + * Start a new namespace. + * + * This also resets the alias table. + * + * @param Name|null $namespace Null is the global namespace + */ + public function startNamespace(Name $namespace = null) + { + $this->namespace = $namespace; + $this->origAliases = $this->aliases = [Stmt\Use_::TYPE_NORMAL => [], Stmt\Use_::TYPE_FUNCTION => [], Stmt\Use_::TYPE_CONSTANT => []]; + } + /** + * Add an alias / import. + * + * @param Name $name Original name + * @param string $aliasName Aliased name + * @param int $type One of Stmt\Use_::TYPE_* + * @param array $errorAttrs Attributes to use to report an error + */ + public function addAlias(Name $name, $aliasName, $type, array $errorAttrs = []) + { + if (!\is_string($aliasName)) { + if (!(\is_string($aliasName) || \is_object($aliasName) && \method_exists($aliasName, '__toString') || (\is_bool($aliasName) || \is_numeric($aliasName)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($aliasName) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($aliasName) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $aliasName = (string) $aliasName; + } + } + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + // Constant names are case sensitive, everything else case insensitive + if ($type === Stmt\Use_::TYPE_CONSTANT) { + $aliasLookupName = $aliasName; + } else { + $aliasLookupName = \strtolower($aliasName); + } + if (isset($this->aliases[$type][$aliasLookupName])) { + $typeStringMap = [Stmt\Use_::TYPE_NORMAL => '', Stmt\Use_::TYPE_FUNCTION => 'function ', Stmt\Use_::TYPE_CONSTANT => 'const ']; + $this->errorHandler->handleError(new Error(\sprintf('Cannot use %s%s as %s because the name is already in use', $typeStringMap[$type], $name, $aliasName), $errorAttrs)); + return; + } + $this->aliases[$type][$aliasLookupName] = $name; + $this->origAliases[$type][$aliasName] = $name; + } + /** + * Get current namespace. + * + * @return null|Name Namespace (or null if global namespace) + */ + public function getNamespace() + { + return $this->namespace; + } + /** + * Get resolved name. + * + * @param Name $name Name to resolve + * @param int $type One of Stmt\Use_::TYPE_{FUNCTION|CONSTANT} + * + * @return null|Name Resolved name, or null if static resolution is not possible + */ + public function getResolvedName(Name $name, $type) + { + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + // don't resolve special class names + if ($type === Stmt\Use_::TYPE_NORMAL && $name->isSpecialClassName()) { + if (!$name->isUnqualified()) { + $this->errorHandler->handleError(new Error(\sprintf("'\\%s' is an invalid class name", $name->toString()), $name->getAttributes())); + } + return $name; + } + // fully qualified names are already resolved + if ($name->isFullyQualified()) { + return $name; + } + // Try to resolve aliases + if (null !== ($resolvedName = $this->resolveAlias($name, $type))) { + return $resolvedName; + } + if ($type !== Stmt\Use_::TYPE_NORMAL && $name->isUnqualified()) { + if (null === $this->namespace) { + // outside of a namespace unaliased unqualified is same as fully qualified + return new FullyQualified($name, $name->getAttributes()); + } + // Cannot resolve statically + return null; + } + // if no alias exists prepend current namespace + return FullyQualified::concat($this->namespace, $name, $name->getAttributes()); + } + /** + * Get resolved class name. + * + * @param Name $name Class ame to resolve + * + * @return Name Resolved name + */ + public function getResolvedClassName(Name $name) + { + $phabelReturn = $this->getResolvedName($name, Stmt\Use_::TYPE_NORMAL); + if (!$phabelReturn instanceof Name) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Name, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Get possible ways of writing a fully qualified name (e.g., by making use of aliases). + * + * @param string $name Fully-qualified name (without leading namespace separator) + * @param int $type One of Stmt\Use_::TYPE_* + * + * @return Name[] Possible representations of the name + */ + public function getPossibleNames($name, $type) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + $lcName = \strtolower($name); + if ($type === Stmt\Use_::TYPE_NORMAL) { + // self, parent and static must always be unqualified + if ($lcName === "self" || $lcName === "parent" || $lcName === "static") { + $phabelReturn = [new Name($name)]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + } + // Collect possible ways to write this name, starting with the fully-qualified name + $possibleNames = [new FullyQualified($name)]; + if (null !== ($nsRelativeName = $this->getNamespaceRelativeName($name, $lcName, $type))) { + // Make sure there is no alias that makes the normally namespace-relative name + // into something else + if (null === $this->resolveAlias($nsRelativeName, $type)) { + $possibleNames[] = $nsRelativeName; + } + } + // Check for relevant namespace use statements + foreach ($this->origAliases[Stmt\Use_::TYPE_NORMAL] as $alias => $orig) { + $lcOrig = $orig->toLowerString(); + if (0 === \strpos($lcName, $lcOrig . '\\')) { + $possibleNames[] = new Name($alias . \substr($name, \strlen($lcOrig))); + } + } + // Check for relevant type-specific use statements + foreach ($this->origAliases[$type] as $alias => $orig) { + if ($type === Stmt\Use_::TYPE_CONSTANT) { + // Constants are are complicated-sensitive + $normalizedOrig = $this->normalizeConstName($orig->toString()); + if ($normalizedOrig === $this->normalizeConstName($name)) { + $possibleNames[] = new Name($alias); + } + } else { + // Everything else is case-insensitive + if ($orig->toLowerString() === $lcName) { + $possibleNames[] = new Name($alias); + } + } + } + $phabelReturn = $possibleNames; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Get shortest representation of this fully-qualified name. + * + * @param string $name Fully-qualified name (without leading namespace separator) + * @param int $type One of Stmt\Use_::TYPE_* + * + * @return Name Shortest representation + */ + public function getShortName($name, $type) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + $possibleNames = $this->getPossibleNames($name, $type); + // Find shortest name + $shortestName = null; + $shortestLength = \INF; + foreach ($possibleNames as $possibleName) { + $length = \strlen($possibleName->toCodeString()); + if ($length < $shortestLength) { + $shortestName = $possibleName; + $shortestLength = $length; + } + } + $phabelReturn = $shortestName; + if (!$phabelReturn instanceof Name) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Name, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function resolveAlias(Name $name, $type) + { + $firstPart = $name->getFirst(); + if ($name->isQualified()) { + // resolve aliases for qualified names, always against class alias table + $checkName = \strtolower($firstPart); + if (isset($this->aliases[Stmt\Use_::TYPE_NORMAL][$checkName])) { + $alias = $this->aliases[Stmt\Use_::TYPE_NORMAL][$checkName]; + return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes()); + } + } elseif ($name->isUnqualified()) { + // constant aliases are case-sensitive, function aliases case-insensitive + $checkName = $type === Stmt\Use_::TYPE_CONSTANT ? $firstPart : \strtolower($firstPart); + if (isset($this->aliases[$type][$checkName])) { + // resolve unqualified aliases + return new FullyQualified($this->aliases[$type][$checkName], $name->getAttributes()); + } + } + // No applicable aliases + return null; + } + private function getNamespaceRelativeName($name, $lcName, $type) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_string($lcName)) { + if (!(\is_string($lcName) || \is_object($lcName) && \method_exists($lcName, '__toString') || (\is_bool($lcName) || \is_numeric($lcName)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($lcName) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($lcName) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $lcName = (string) $lcName; + } + } + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + if (null === $this->namespace) { + return new Name($name); + } + if ($type === Stmt\Use_::TYPE_CONSTANT) { + // The constants true/false/null always resolve to the global symbols, even inside a + // namespace, so they may be used without qualification + if ($lcName === "true" || $lcName === "false" || $lcName === "null") { + return new Name($name); + } + } + $namespacePrefix = \strtolower($this->namespace . '\\'); + if (0 === \strpos($lcName, $namespacePrefix)) { + return new Name(\substr($name, \strlen($namespacePrefix))); + } + return null; + } + private function normalizeConstName($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $nsSep = \strrpos($name, '\\'); + if (\false === $nsSep) { + return $name; + } + // Constants have case-insensitive namespace and case-sensitive short-name + $ns = \substr($name, 0, $nsSep); + $shortName = \substr($name, $nsSep + 1); + return \strtolower($ns) . '\\' . $shortName; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node.php new file mode 100644 index 000000000..b93cb8e6f --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node.php @@ -0,0 +1,135 @@ +attributes = $attributes; + $this->name = $name; + $this->value = $value; + $this->byRef = $byRef; + $this->unpack = $unpack; + } + public function getSubNodeNames() + { + $phabelReturn = ['name', 'value', 'byRef', 'unpack']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Arg'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Attribute.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Attribute.php new file mode 100644 index 000000000..027447cf8 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Attribute.php @@ -0,0 +1,44 @@ +attributes = $attributes; + $this->name = $name; + $this->args = $args; + } + public function getSubNodeNames() + { + $phabelReturn = ['name', 'args']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Attribute'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/AttributeGroup.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/AttributeGroup.php new file mode 100644 index 000000000..f0212f6ec --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/AttributeGroup.php @@ -0,0 +1,40 @@ +attributes = $attributes; + $this->attrs = $attrs; + } + public function getSubNodeNames() + { + $phabelReturn = ['attrs']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'AttributeGroup'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Const_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Const_.php new file mode 100644 index 000000000..73c3224e5 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Const_.php @@ -0,0 +1,48 @@ +attributes = $attributes; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->value = $value; + } + public function getSubNodeNames() + { + $phabelReturn = ['name', 'value']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Const'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr.php new file mode 100644 index 000000000..83a06ffb7 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr.php @@ -0,0 +1,8 @@ +attributes = $attributes; + $this->var = $var; + $this->dim = $dim; + } + public function getSubNodeNames() + { + $phabelReturn = ['var', 'dim']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_ArrayDimFetch'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php new file mode 100644 index 000000000..7e9e034f8 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php @@ -0,0 +1,66 @@ +attributes = $attributes; + $this->key = $key; + $this->value = $value; + $this->byRef = $byRef; + $this->unpack = $unpack; + } + public function getSubNodeNames() + { + $phabelReturn = ['key', 'value', 'byRef', 'unpack']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_ArrayItem'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Array_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Array_.php new file mode 100644 index 000000000..dafe7286d --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Array_.php @@ -0,0 +1,46 @@ +attributes = $attributes; + $this->items = $items; + } + public function getSubNodeNames() + { + $phabelReturn = ['items']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Array'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php new file mode 100644 index 000000000..b0a49075d --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php @@ -0,0 +1,106 @@ + false : Whether the closure is static + * 'byRef' => false : Whether to return by reference + * 'params' => array() : Parameters + * 'returnType' => null : Return type + * 'expr' => Expr : Expression body + * 'attrGroups' => array() : PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct(array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->static = isset($subNodes['static']) ? $subNodes['static'] : \false; + $this->byRef = isset($subNodes['byRef']) ? $subNodes['byRef'] : \false; + $this->params = isset($subNodes['params']) ? $subNodes['params'] : []; + $returnType = isset($subNodes['returnType']) ? $subNodes['returnType'] : null; + $this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType; + $this->expr = isset($subNodes['expr']) ? $subNodes['expr'] : null; + $this->attrGroups = isset($subNodes['attrGroups']) ? $subNodes['attrGroups'] : []; + } + public function getSubNodeNames() + { + $phabelReturn = ['attrGroups', 'static', 'byRef', 'params', 'returnType', 'expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function returnsByRef() + { + $phabelReturn = $this->byRef; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function getParams() + { + $phabelReturn = $this->params; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getReturnType() + { + return $this->returnType; + } + public function getAttrGroups() + { + $phabelReturn = $this->attrGroups; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return Node\Stmt\Return_[] + */ + public function getStmts() + { + $phabelReturn = [new Node\Stmt\Return_($this->expr)]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_ArrowFunction'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Assign.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Assign.php new file mode 100644 index 000000000..d6e190b89 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Assign.php @@ -0,0 +1,45 @@ +attributes = $attributes; + $this->var = $var; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['var', 'expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Assign'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/AssignOp.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/AssignOp.php new file mode 100644 index 000000000..32c3fa8db --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/AssignOp.php @@ -0,0 +1,33 @@ +attributes = $attributes; + $this->var = $var; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['var', 'expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php new file mode 100644 index 000000000..ed4e1266c --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php @@ -0,0 +1,20 @@ +attributes = $attributes; + $this->var = $var; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['var', 'expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_AssignRef'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp.php new file mode 100644 index 000000000..9578a1cf3 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp.php @@ -0,0 +1,42 @@ +attributes = $attributes; + $this->left = $left; + $this->right = $right; + } + public function getSubNodeNames() + { + $phabelReturn = ['left', 'right']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Get the operator sigil for this binary operation. + * + * In the case there are multiple possible sigils for an operator, this method does not + * necessarily return the one used in the parsed code. + * + * @return string + */ + public abstract function getOperatorSigil(); +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php new file mode 100644 index 000000000..37fa4083c --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php @@ -0,0 +1,32 @@ +'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_BinaryOp_Greater'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php new file mode 100644 index 000000000..d62b553bb --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php @@ -0,0 +1,32 @@ +='; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_BinaryOp_GreaterOrEqual'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.php new file mode 100644 index 000000000..7a57a86af --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.php @@ -0,0 +1,32 @@ +>'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_BinaryOp_ShiftRight'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.php new file mode 100644 index 000000000..1a268533c --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.php @@ -0,0 +1,32 @@ +'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_BinaryOp_Spaceship'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.php new file mode 100644 index 000000000..1c285e41d --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_BitwiseNot'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BooleanNot.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BooleanNot.php new file mode 100644 index 000000000..e020ee780 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/BooleanNot.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_BooleanNot'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Cast.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Cast.php new file mode 100644 index 000000000..c8e491485 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Cast.php @@ -0,0 +1,29 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.php new file mode 100644 index 000000000..349701852 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.php @@ -0,0 +1,20 @@ +attributes = $attributes; + $this->class = $class; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames() + { + $phabelReturn = ['class', 'name']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_ClassConstFetch'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Clone_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Clone_.php new file mode 100644 index 000000000..d65abaff1 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Clone_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Clone'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Closure.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Closure.php new file mode 100644 index 000000000..df267355f --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Closure.php @@ -0,0 +1,110 @@ + false : Whether the closure is static + * 'byRef' => false : Whether to return by reference + * 'params' => array(): Parameters + * 'uses' => array(): use()s + * 'returnType' => null : Return type + * 'stmts' => array(): Statements + * 'attrGroups' => array(): PHP attributes groups + * @param array $attributes Additional attributes + */ + public function __construct(array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->static = isset($subNodes['static']) ? $subNodes['static'] : \false; + $this->byRef = isset($subNodes['byRef']) ? $subNodes['byRef'] : \false; + $this->params = isset($subNodes['params']) ? $subNodes['params'] : []; + $this->uses = isset($subNodes['uses']) ? $subNodes['uses'] : []; + $returnType = isset($subNodes['returnType']) ? $subNodes['returnType'] : null; + $this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType; + $this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : []; + $this->attrGroups = isset($subNodes['attrGroups']) ? $subNodes['attrGroups'] : []; + } + public function getSubNodeNames() + { + $phabelReturn = ['attrGroups', 'static', 'byRef', 'params', 'uses', 'returnType', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function returnsByRef() + { + $phabelReturn = $this->byRef; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function getParams() + { + $phabelReturn = $this->params; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getReturnType() + { + return $this->returnType; + } + /** @return Node\Stmt[] */ + public function getStmts() + { + $phabelReturn = $this->stmts; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getAttrGroups() + { + $phabelReturn = $this->attrGroups; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Closure'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php new file mode 100644 index 000000000..09715e555 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php @@ -0,0 +1,52 @@ +attributes = $attributes; + $this->var = $var; + $this->byRef = $byRef; + } + public function getSubNodeNames() + { + $phabelReturn = ['var', 'byRef']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_ClosureUse'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ConstFetch.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ConstFetch.php new file mode 100644 index 000000000..3276c5449 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ConstFetch.php @@ -0,0 +1,42 @@ +attributes = $attributes; + $this->name = $name; + } + public function getSubNodeNames() + { + $phabelReturn = ['name']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_ConstFetch'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Empty_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Empty_.php new file mode 100644 index 000000000..9845a31ef --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Empty_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Empty'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Error.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Error.php new file mode 100644 index 000000000..85b340e22 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Error.php @@ -0,0 +1,43 @@ +attributes = $attributes; + } + public function getSubNodeNames() + { + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Error'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.php new file mode 100644 index 000000000..c04d07fd2 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_ErrorSuppress'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Eval_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Eval_.php new file mode 100644 index 000000000..102c6b842 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Eval_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Eval'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Exit_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Exit_.php new file mode 100644 index 000000000..7b1f75c94 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Exit_.php @@ -0,0 +1,44 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Exit'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/FuncCall.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/FuncCall.php new file mode 100644 index 000000000..ca3867cdf --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/FuncCall.php @@ -0,0 +1,46 @@ +attributes = $attributes; + $this->name = $name; + $this->args = $args; + } + public function getSubNodeNames() + { + $phabelReturn = ['name', 'args']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_FuncCall'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Include_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Include_.php new file mode 100644 index 000000000..3da51310f --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Include_.php @@ -0,0 +1,56 @@ +attributes = $attributes; + $this->expr = $expr; + $this->type = $type; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr', 'type']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Include'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Instanceof_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Instanceof_.php new file mode 100644 index 000000000..244c22bc1 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Instanceof_.php @@ -0,0 +1,46 @@ +attributes = $attributes; + $this->expr = $expr; + $this->class = $class; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr', 'class']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Instanceof'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Isset_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Isset_.php new file mode 100644 index 000000000..271d96d54 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Isset_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->vars = $vars; + } + public function getSubNodeNames() + { + $phabelReturn = ['vars']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Isset'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/List_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/List_.php new file mode 100644 index 000000000..e325e3362 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/List_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->items = $items; + } + public function getSubNodeNames() + { + $phabelReturn = ['items']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_List'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Match_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Match_.php new file mode 100644 index 000000000..dd07c1cca --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Match_.php @@ -0,0 +1,42 @@ +attributes = $attributes; + $this->cond = $cond; + $this->arms = $arms; + } + public function getSubNodeNames() + { + $phabelReturn = ['cond', 'arms']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Match'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/MethodCall.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/MethodCall.php new file mode 100644 index 000000000..cfc83d89f --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/MethodCall.php @@ -0,0 +1,51 @@ +attributes = $attributes; + $this->var = $var; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->args = $args; + } + public function getSubNodeNames() + { + $phabelReturn = ['var', 'name', 'args']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_MethodCall'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/New_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/New_.php new file mode 100644 index 000000000..6cbebe436 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/New_.php @@ -0,0 +1,46 @@ +attributes = $attributes; + $this->class = $class; + $this->args = $args; + } + public function getSubNodeNames() + { + $phabelReturn = ['class', 'args']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_New'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.php new file mode 100644 index 000000000..2c4ae97bf --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.php @@ -0,0 +1,51 @@ +attributes = $attributes; + $this->var = $var; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->args = $args; + } + public function getSubNodeNames() + { + $phabelReturn = ['var', 'name', 'args']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_NullsafeMethodCall'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.php new file mode 100644 index 000000000..42b968e30 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.php @@ -0,0 +1,46 @@ +attributes = $attributes; + $this->var = $var; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames() + { + $phabelReturn = ['var', 'name']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_NullsafePropertyFetch'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PostDec.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PostDec.php new file mode 100644 index 000000000..073bb1739 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PostDec.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->var = $var; + } + public function getSubNodeNames() + { + $phabelReturn = ['var']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_PostDec'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PostInc.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PostInc.php new file mode 100644 index 000000000..fd15d9abe --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PostInc.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->var = $var; + } + public function getSubNodeNames() + { + $phabelReturn = ['var']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_PostInc'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PreDec.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PreDec.php new file mode 100644 index 000000000..50b858239 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PreDec.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->var = $var; + } + public function getSubNodeNames() + { + $phabelReturn = ['var']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_PreDec'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PreInc.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PreInc.php new file mode 100644 index 000000000..694291a0a --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PreInc.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->var = $var; + } + public function getSubNodeNames() + { + $phabelReturn = ['var']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_PreInc'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Print_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Print_.php new file mode 100644 index 000000000..d3b6b6a86 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Print_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Print'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.php new file mode 100644 index 000000000..df24df6e5 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.php @@ -0,0 +1,46 @@ +attributes = $attributes; + $this->var = $var; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames() + { + $phabelReturn = ['var', 'name']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_PropertyFetch'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ShellExec.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ShellExec.php new file mode 100644 index 000000000..0ed573d87 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/ShellExec.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->parts = $parts; + } + public function getSubNodeNames() + { + $phabelReturn = ['parts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_ShellExec'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/StaticCall.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/StaticCall.php new file mode 100644 index 000000000..bdc3187c5 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/StaticCall.php @@ -0,0 +1,51 @@ +attributes = $attributes; + $this->class = $class; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->args = $args; + } + public function getSubNodeNames() + { + $phabelReturn = ['class', 'name', 'args']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_StaticCall'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.php new file mode 100644 index 000000000..521f87fe5 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.php @@ -0,0 +1,47 @@ +attributes = $attributes; + $this->class = $class; + $this->name = \is_string($name) ? new VarLikeIdentifier($name) : $name; + } + public function getSubNodeNames() + { + $phabelReturn = ['class', 'name']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_StaticPropertyFetch'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Ternary.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Ternary.php new file mode 100644 index 000000000..71c5f6e3f --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Ternary.php @@ -0,0 +1,49 @@ +attributes = $attributes; + $this->cond = $cond; + $this->if = $if; + $this->else = $else; + } + public function getSubNodeNames() + { + $phabelReturn = ['cond', 'if', 'else']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Ternary'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Throw_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Throw_.php new file mode 100644 index 000000000..ad48442fa --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Throw_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Throw'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.php new file mode 100644 index 000000000..c8e452ae5 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_UnaryMinus'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.php new file mode 100644 index 000000000..c1aacdc6c --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_UnaryPlus'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Variable.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Variable.php new file mode 100644 index 000000000..7664b3f13 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Variable.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->name = $name; + } + public function getSubNodeNames() + { + $phabelReturn = ['name']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Variable'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/YieldFrom.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/YieldFrom.php new file mode 100644 index 000000000..9ba064af2 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/YieldFrom.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_YieldFrom'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Yield_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Yield_.php new file mode 100644 index 000000000..2f5ca54b6 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Expr/Yield_.php @@ -0,0 +1,45 @@ +attributes = $attributes; + $this->key = $key; + $this->value = $value; + } + public function getSubNodeNames() + { + $phabelReturn = ['key', 'value']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Expr_Yield'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/FunctionLike.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/FunctionLike.php new file mode 100644 index 000000000..225b498b3 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/FunctionLike.php @@ -0,0 +1,38 @@ + \true, 'parent' => \true, 'static' => \true]; + /** + * Constructs an identifier node. + * + * @param string $name Identifier as string + * @param array $attributes Additional attributes + */ + public function __construct($name, array $attributes = []) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $this->attributes = $attributes; + $this->name = $name; + } + public function getSubNodeNames() + { + $phabelReturn = ['name']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Get identifier as string. + * + * @return string Identifier as string. + */ + public function toString() + { + $phabelReturn = $this->name; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Get lowercased identifier as string. + * + * @return string Lowercased identifier as string + */ + public function toLowerString() + { + $phabelReturn = \strtolower($this->name); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Checks whether the identifier is a special class name (self, parent or static). + * + * @return bool Whether identifier is a special class name + */ + public function isSpecialClassName() + { + $phabelReturn = isset(self::$specialClassNames[\strtolower($this->name)]); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Get identifier as string. + * + * @return string Identifier as string + */ + public function __toString() + { + $phabelReturn = $this->name; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Identifier'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/MatchArm.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/MatchArm.php new file mode 100644 index 000000000..7b80cfa29 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/MatchArm.php @@ -0,0 +1,42 @@ +conds = $conds; + $this->body = $body; + $this->attributes = $attributes; + } + public function getSubNodeNames() + { + $phabelReturn = ['conds', 'body']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'MatchArm'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Name.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Name.php new file mode 100644 index 000000000..57645dcf0 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Name.php @@ -0,0 +1,353 @@ + \true, 'parent' => \true, 'static' => \true]; + /** + * Constructs a name node. + * + * @param string|string[]|self $name Name as string, part array or Name instance (copy ctor) + * @param array $attributes Additional attributes + */ + public function __construct($name, array $attributes = []) + { + $this->attributes = $attributes; + $this->parts = self::prepareName($name); + } + public function getSubNodeNames() + { + $phabelReturn = ['parts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Gets the first part of the name, i.e. everything before the first namespace separator. + * + * @return string First part of the name + */ + public function getFirst() + { + $phabelReturn = $this->parts[0]; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the last part of the name, i.e. everything after the last namespace separator. + * + * @return string Last part of the name + */ + public function getLast() + { + $phabelReturn = $this->parts[\count($this->parts) - 1]; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Checks whether the name is unqualified. (E.g. Name) + * + * @return bool Whether the name is unqualified + */ + public function isUnqualified() + { + $phabelReturn = 1 === \count($this->parts); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Checks whether the name is qualified. (E.g. Name\Name) + * + * @return bool Whether the name is qualified + */ + public function isQualified() + { + $phabelReturn = 1 < \count($this->parts); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Checks whether the name is fully qualified. (E.g. \Name) + * + * @return bool Whether the name is fully qualified + */ + public function isFullyQualified() + { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Checks whether the name is explicitly relative to the current namespace. (E.g. namespace\Name) + * + * @return bool Whether the name is relative + */ + public function isRelative() + { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Returns a string representation of the name itself, without taking the name type into + * account (e.g., not including a leading backslash for fully qualified names). + * + * @return string String representation + */ + public function toString() + { + $phabelReturn = \implode('\\', $this->parts); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Returns a string representation of the name as it would occur in code (e.g., including + * leading backslash for fully qualified names. + * + * @return string String representation + */ + public function toCodeString() + { + $phabelReturn = $this->toString(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Returns lowercased string representation of the name, without taking the name type into + * account (e.g., no leading backslash for fully qualified names). + * + * @return string Lowercased string representation + */ + public function toLowerString() + { + $phabelReturn = \strtolower(\implode('\\', $this->parts)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Checks whether the identifier is a special class name (self, parent or static). + * + * @return bool Whether identifier is a special class name + */ + public function isSpecialClassName() + { + $phabelReturn = \count($this->parts) === 1 && isset(self::$specialClassNames[\strtolower($this->parts[0])]); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Returns a string representation of the name by imploding the namespace parts with the + * namespace separator. + * + * @return string String representation + */ + public function __toString() + { + $phabelReturn = \implode('\\', $this->parts); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets a slice of a name (similar to array_slice). + * + * This method returns a new instance of the same type as the original and with the same + * attributes. + * + * If the slice is empty, null is returned. The null value will be correctly handled in + * concatenations using concat(). + * + * Offset and length have the same meaning as in array_slice(). + * + * @param int $offset Offset to start the slice at (may be negative) + * @param int|null $length Length of the slice (may be negative) + * + * @return static|null Sliced name + */ + public function slice($offset, $length = null) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + } + $numParts = \count($this->parts); + $realOffset = $offset < 0 ? $offset + $numParts : $offset; + if ($realOffset < 0 || $realOffset > $numParts) { + throw new \OutOfBoundsException(\sprintf('Offset %d is out of bounds', $offset)); + } + if (null === $length) { + $realLength = $numParts - $realOffset; + } else { + $realLength = $length < 0 ? $length + $numParts - $realOffset : $length; + if ($realLength < 0 || $realLength > $numParts) { + throw new \OutOfBoundsException(\sprintf('Length %d is out of bounds', $length)); + } + } + if ($realLength === 0) { + // Empty slice is represented as null + return null; + } + return new static(\array_slice($this->parts, $realOffset, $realLength), $this->attributes); + } + /** + * Concatenate two names, yielding a new Name instance. + * + * The type of the generated instance depends on which class this method is called on, for + * example Name\FullyQualified::concat() will yield a Name\FullyQualified instance. + * + * If one of the arguments is null, a new instance of the other name will be returned. If both + * arguments are null, null will be returned. As such, writing + * Name::concat($namespace, $shortName) + * where $namespace is a Name node or null will work as expected. + * + * @param string|string[]|self|null $name1 The first name + * @param string|string[]|self|null $name2 The second name + * @param array $attributes Attributes to assign to concatenated name + * + * @return static|null Concatenated name + */ + public static function concat($name1, $name2, array $attributes = []) + { + if (null === $name1 && null === $name2) { + return null; + } elseif (null === $name1) { + return new static(self::prepareName($name2), $attributes); + } elseif (null === $name2) { + return new static(self::prepareName($name1), $attributes); + } else { + return new static(\array_merge(self::prepareName($name1), self::prepareName($name2)), $attributes); + } + } + /** + * Prepares a (string, array or Name node) name for use in name changing methods by converting + * it to an array. + * + * @param string|string[]|self $name Name to prepare + * + * @return string[] Prepared name + */ + private static function prepareName($name) + { + if (\is_string($name)) { + if ('' === $name) { + throw new \InvalidArgumentException('Name cannot be empty'); + } + $phabelReturn = \explode('\\', $name); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } elseif (\is_array($name)) { + if (empty($name)) { + throw new \InvalidArgumentException('Name cannot be empty'); + } + $phabelReturn = $name; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } elseif ($name instanceof self) { + $phabelReturn = $name->parts; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + throw new \InvalidArgumentException('Expected string, array of parts or Name instance'); + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + public function getType() + { + $phabelReturn = 'Name'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Name/FullyQualified.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Name/FullyQualified.php new file mode 100644 index 000000000..4e56bbbfb --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Name/FullyQualified.php @@ -0,0 +1,99 @@ +toString(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Name_FullyQualified'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Name/Relative.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Name/Relative.php new file mode 100644 index 000000000..66ef7f931 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Name/Relative.php @@ -0,0 +1,99 @@ +toString(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Name_Relative'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/NullableType.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/NullableType.php new file mode 100644 index 000000000..80d4c7c74 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/NullableType.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->type = \is_string($type) ? new Identifier($type) : $type; + } + public function getSubNodeNames() + { + $phabelReturn = ['type']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'NullableType'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Param.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Param.php new file mode 100644 index 000000000..26e6ad666 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Param.php @@ -0,0 +1,86 @@ +attributes = $attributes; + $this->type = \is_string($type) ? new Identifier($type) : $type; + $this->byRef = $byRef; + $this->variadic = $variadic; + $this->var = $var; + $this->default = $default; + $this->flags = $flags; + $this->attrGroups = $attrGroups; + } + public function getSubNodeNames() + { + $phabelReturn = ['attrGroups', 'flags', 'type', 'byRef', 'variadic', 'var', 'default']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Param'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar.php new file mode 100644 index 000000000..ad9366b65 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar.php @@ -0,0 +1,7 @@ +attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames() + { + $phabelReturn = ['value']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @internal + * + * Parses a DNUMBER token like PHP would. + * + * @param string $str A string number + * + * @return float The parsed number + */ + public static function parse($str) + { + if (!\is_string($str)) { + if (!(\is_string($str) || \is_object($str) && \method_exists($str, '__toString') || (\is_bool($str) || \is_numeric($str)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($str) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($str) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $str = (string) $str; + } + } + $str = \str_replace('_', '', $str); + // if string contains any of .eE just cast it to float + if (\false !== \strpbrk($str, '.eE')) { + $phabelReturn = (float) $str; + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } + // otherwise it's an integer notation that overflowed into a float + // if it starts with 0 it's one of the special integer notations + if ('0' === $str[0]) { + // hex + if ('x' === $str[1] || 'X' === $str[1]) { + $phabelReturn = \hexdec($str); + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } + // bin + if ('b' === $str[1] || 'B' === $str[1]) { + $phabelReturn = \bindec($str); + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \octdec(\substr($str, 0, \strcspn($str, '89'))); + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + // oct + // substr($str, 0, strcspn($str, '89')) cuts the string at the first invalid digit (8 or 9) + // so that only the digits before that are used + return $phabelReturn; + } + $phabelReturn = (float) $str; + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + // dec + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Scalar_DNumber'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php new file mode 100644 index 000000000..66481715d --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php @@ -0,0 +1,42 @@ +attributes = $attributes; + $this->parts = $parts; + } + public function getSubNodeNames() + { + $phabelReturn = ['parts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Scalar_Encapsed'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php new file mode 100644 index 000000000..39b92e67a --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php @@ -0,0 +1,48 @@ +attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames() + { + $phabelReturn = ['value']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Scalar_EncapsedStringPart'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/LNumber.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/LNumber.php new file mode 100644 index 000000000..2a93c9def --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/LNumber.php @@ -0,0 +1,115 @@ +attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames() + { + $phabelReturn = ['value']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Constructs an LNumber node from a string number literal. + * + * @param string $str String number literal (decimal, octal, hex or binary) + * @param array $attributes Additional attributes + * @param bool $allowInvalidOctal Whether to allow invalid octal numbers (PHP 5) + * + * @return LNumber The constructed LNumber, including kind attribute + */ + public static function fromString($str, array $attributes = [], $allowInvalidOctal = \false) + { + if (!\is_string($str)) { + if (!(\is_string($str) || \is_object($str) && \method_exists($str, '__toString') || (\is_bool($str) || \is_numeric($str)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($str) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($str) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $str = (string) $str; + } + } + if (!\is_bool($allowInvalidOctal)) { + if (!(\is_bool($allowInvalidOctal) || \is_numeric($allowInvalidOctal) || \is_string($allowInvalidOctal))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($allowInvalidOctal) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($allowInvalidOctal) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $allowInvalidOctal = (bool) $allowInvalidOctal; + } + } + $str = \str_replace('_', '', $str); + if ('0' !== $str[0] || '0' === $str) { + $attributes['kind'] = LNumber::KIND_DEC; + $phabelReturn = new LNumber((int) $str, $attributes); + if (!$phabelReturn instanceof LNumber) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type LNumber, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ('x' === $str[1] || 'X' === $str[1]) { + $attributes['kind'] = LNumber::KIND_HEX; + $phabelReturn = new LNumber(\hexdec($str), $attributes); + if (!$phabelReturn instanceof LNumber) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type LNumber, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ('b' === $str[1] || 'B' === $str[1]) { + $attributes['kind'] = LNumber::KIND_BIN; + $phabelReturn = new LNumber(\bindec($str), $attributes); + if (!$phabelReturn instanceof LNumber) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type LNumber, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if (!$allowInvalidOctal && \strpbrk($str, '89')) { + throw new Error('Invalid numeric literal', $attributes); + } + // use intval instead of octdec to get proper cutting behavior with malformed numbers + $attributes['kind'] = LNumber::KIND_OCT; + $phabelReturn = new LNumber(\intval($str, 8), $attributes); + if (!$phabelReturn instanceof LNumber) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type LNumber, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Scalar_LNumber'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/MagicConst.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/MagicConst.php new file mode 100644 index 000000000..95fa75423 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/MagicConst.php @@ -0,0 +1,31 @@ +attributes = $attributes; + } + public function getSubNodeNames() + { + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Get name of magic constant. + * + * @return string Name of magic constant + */ + public abstract function getName(); +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.php new file mode 100644 index 000000000..32715886a --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.php @@ -0,0 +1,32 @@ + '\\', '$' => '$', 'n' => "\n", 'r' => "\r", 't' => "\t", 'f' => "\f", 'v' => "\v", 'e' => "\x1b"]; + /** + * Constructs a string scalar node. + * + * @param string $value Value of the string + * @param array $attributes Additional attributes + */ + public function __construct($value, array $attributes = []) + { + if (!\is_string($value)) { + if (!(\is_string($value) || \is_object($value) && \method_exists($value, '__toString') || (\is_bool($value) || \is_numeric($value)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($value) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($value) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $value = (string) $value; + } + } + $this->attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames() + { + $phabelReturn = ['value']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @internal + * + * Parses a string token. + * + * @param string $str String token content + * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes + * + * @return string The parsed string + */ + public static function parse($str, $parseUnicodeEscape = \true) + { + if (!\is_string($str)) { + if (!(\is_string($str) || \is_object($str) && \method_exists($str, '__toString') || (\is_bool($str) || \is_numeric($str)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($str) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($str) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $str = (string) $str; + } + } + if (!\is_bool($parseUnicodeEscape)) { + if (!(\is_bool($parseUnicodeEscape) || \is_numeric($parseUnicodeEscape) || \is_string($parseUnicodeEscape))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($parseUnicodeEscape) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($parseUnicodeEscape) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $parseUnicodeEscape = (bool) $parseUnicodeEscape; + } + } + $bLength = 0; + if ('b' === $str[0] || 'B' === $str[0]) { + $bLength = 1; + } + if ('\'' === $str[$bLength]) { + $phabelReturn = \str_replace(['\\\\', '\\\''], ['\\', '\''], \substr($str, $bLength + 1, -1)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } else { + $phabelReturn = self::parseEscapeSequences(\substr($str, $bLength + 1, -1), '"', $parseUnicodeEscape); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** + * @internal + * + * Parses escape sequences in strings (all string types apart from single quoted). + * + * @param string $str String without quotes + * @param null|string $quote Quote type + * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes + * + * @return string String with escape sequences parsed + */ + public static function parseEscapeSequences($str, $quote, $parseUnicodeEscape = \true) + { + if (!\is_string($str)) { + if (!(\is_string($str) || \is_object($str) && \method_exists($str, '__toString') || (\is_bool($str) || \is_numeric($str)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($str) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($str) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $str = (string) $str; + } + } + if (!\is_bool($parseUnicodeEscape)) { + if (!(\is_bool($parseUnicodeEscape) || \is_numeric($parseUnicodeEscape) || \is_string($parseUnicodeEscape))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($parseUnicodeEscape) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($parseUnicodeEscape) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $parseUnicodeEscape = (bool) $parseUnicodeEscape; + } + } + if (null !== $quote) { + $str = \str_replace('\\' . $quote, $quote, $str); + } + $extra = ''; + if ($parseUnicodeEscape) { + $extra = '|u\\{([0-9a-fA-F]+)\\}'; + } + $phabelReturn = \preg_replace_callback('~\\\\([\\\\$nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}' . $extra . ')~', function ($matches) { + $str = $matches[1]; + if (isset(self::$replacements[$str])) { + return self::$replacements[$str]; + } elseif ('x' === $str[0] || 'X' === $str[0]) { + return \chr(\hexdec(\substr($str, 1))); + } elseif ('u' === $str[0]) { + return self::codePointToUtf8(\hexdec($matches[2])); + } else { + return \chr(\octdec($str)); + } + }, $str); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Converts a Unicode code point to its UTF-8 encoded representation. + * + * @param int $num Code point + * + * @return string UTF-8 representation of code point + */ + private static function codePointToUtf8($num) + { + if (!\is_int($num)) { + if (!(\is_bool($num) || \is_numeric($num))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($num) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($num) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $num = (int) $num; + } + } + if ($num <= 0x7f) { + $phabelReturn = \chr($num); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if ($num <= 0x7ff) { + $phabelReturn = \chr(($num >> 6) + 0xc0) . \chr(($num & 0x3f) + 0x80); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if ($num <= 0xffff) { + $phabelReturn = \chr(($num >> 12) + 0xe0) . \chr(($num >> 6 & 0x3f) + 0x80) . \chr(($num & 0x3f) + 0x80); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if ($num <= 0x1fffff) { + $phabelReturn = \chr(($num >> 18) + 0xf0) . \chr(($num >> 12 & 0x3f) + 0x80) . \chr(($num >> 6 & 0x3f) + 0x80) . \chr(($num & 0x3f) + 0x80); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + throw new Error('Invalid UTF-8 codepoint escape sequence: Codepoint too large'); + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + public function getType() + { + $phabelReturn = 'Scalar_String'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt.php new file mode 100644 index 000000000..4d81d63bc --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt.php @@ -0,0 +1,8 @@ +attributes = $attributes; + $this->num = $num; + } + public function getSubNodeNames() + { + $phabelReturn = ['num']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Break'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Case_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Case_.php new file mode 100644 index 000000000..900e5296d --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Case_.php @@ -0,0 +1,45 @@ +attributes = $attributes; + $this->cond = $cond; + $this->stmts = $stmts; + } + public function getSubNodeNames() + { + $phabelReturn = ['cond', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Case'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Catch_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Catch_.php new file mode 100644 index 000000000..bcc775343 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Catch_.php @@ -0,0 +1,50 @@ +attributes = $attributes; + $this->types = $types; + $this->var = $var; + $this->stmts = $stmts; + } + public function getSubNodeNames() + { + $phabelReturn = ['types', 'var', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Catch'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php new file mode 100644 index 000000000..db46d979d --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php @@ -0,0 +1,107 @@ +attributes = $attributes; + $this->flags = $flags; + $this->consts = $consts; + $this->attrGroups = $attrGroups; + } + public function getSubNodeNames() + { + $phabelReturn = ['attrGroups', 'flags', 'consts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Whether constant is explicitly or implicitly public. + * + * @return bool + */ + public function isPublic() + { + $phabelReturn = ($this->flags & Class_::MODIFIER_PUBLIC) !== 0 || ($this->flags & Class_::VISIBILITY_MODIFIER_MASK) === 0; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether constant is protected. + * + * @return bool + */ + public function isProtected() + { + $phabelReturn = (bool) ($this->flags & Class_::MODIFIER_PROTECTED); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether constant is private. + * + * @return bool + */ + public function isPrivate() + { + $phabelReturn = (bool) ($this->flags & Class_::MODIFIER_PRIVATE); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_ClassConst'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php new file mode 100644 index 000000000..c1a03474f --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php @@ -0,0 +1,138 @@ +stmts as $stmt) { + if ($stmt instanceof TraitUse) { + $traitUses[] = $stmt; + } + } + $phabelReturn = $traitUses; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return ClassConst[] + */ + public function getConstants() + { + $constants = []; + foreach ($this->stmts as $stmt) { + if ($stmt instanceof ClassConst) { + $constants[] = $stmt; + } + } + $phabelReturn = $constants; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return Property[] + */ + public function getProperties() + { + $properties = []; + foreach ($this->stmts as $stmt) { + if ($stmt instanceof Property) { + $properties[] = $stmt; + } + } + $phabelReturn = $properties; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Gets property with the given name defined directly in this class/interface/trait. + * + * @param string $name Name of the property + * + * @return Property|null Property node or null if the property does not exist + */ + public function getProperty($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + foreach ($this->stmts as $stmt) { + if ($stmt instanceof Property) { + foreach ($stmt->props as $prop) { + if ($prop instanceof PropertyProperty && $name === $prop->name->toString()) { + return $stmt; + } + } + } + } + return null; + } + /** + * Gets all methods defined directly in this class/interface/trait + * + * @return ClassMethod[] + */ + public function getMethods() + { + $methods = []; + foreach ($this->stmts as $stmt) { + if ($stmt instanceof ClassMethod) { + $methods[] = $stmt; + } + } + $phabelReturn = $methods; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Gets method with the given name defined directly in this class/interface/trait. + * + * @param string $name Name of the method (compared case-insensitively) + * + * @return ClassMethod|null Method node or null if the method does not exist + */ + public function getMethod($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $lowerName = \strtolower($name); + foreach ($this->stmts as $stmt) { + if ($stmt instanceof ClassMethod && $lowerName === $stmt->name->toLowerString()) { + return $stmt; + } + } + return null; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php new file mode 100644 index 000000000..b4df3d1f6 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php @@ -0,0 +1,224 @@ + \true, '__destruct' => \true, '__call' => \true, '__callstatic' => \true, '__get' => \true, '__set' => \true, '__isset' => \true, '__unset' => \true, '__sleep' => \true, '__wakeup' => \true, '__tostring' => \true, '__set_state' => \true, '__clone' => \true, '__invoke' => \true, '__debuginfo' => \true]; + /** + * Constructs a class method node. + * + * @param string|Node\Identifier $name Name + * @param array $subNodes Array of the following optional subnodes: + * 'flags => MODIFIER_PUBLIC: Flags + * 'byRef' => false : Whether to return by reference + * 'params' => array() : Parameters + * 'returnType' => null : Return type + * 'stmts' => array() : Statements + * 'attrGroups' => array() : PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->flags = isset($subNodes['flags']) ? $subNodes['flags'] : (isset($subNodes['type']) ? $subNodes['type'] : 0); + $this->byRef = isset($subNodes['byRef']) ? $subNodes['byRef'] : \false; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->params = isset($subNodes['params']) ? $subNodes['params'] : []; + $returnType = isset($subNodes['returnType']) ? $subNodes['returnType'] : null; + $this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType; + $this->stmts = \array_key_exists('stmts', $subNodes) ? $subNodes['stmts'] : []; + $this->attrGroups = isset($subNodes['attrGroups']) ? $subNodes['attrGroups'] : []; + } + public function getSubNodeNames() + { + $phabelReturn = ['attrGroups', 'flags', 'byRef', 'name', 'params', 'returnType', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function returnsByRef() + { + $phabelReturn = $this->byRef; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function getParams() + { + $phabelReturn = $this->params; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getReturnType() + { + return $this->returnType; + } + public function getStmts() + { + return $this->stmts; + } + public function getAttrGroups() + { + $phabelReturn = $this->attrGroups; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Whether the method is explicitly or implicitly public. + * + * @return bool + */ + public function isPublic() + { + $phabelReturn = ($this->flags & Class_::MODIFIER_PUBLIC) !== 0 || ($this->flags & Class_::VISIBILITY_MODIFIER_MASK) === 0; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether the method is protected. + * + * @return bool + */ + public function isProtected() + { + $phabelReturn = (bool) ($this->flags & Class_::MODIFIER_PROTECTED); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether the method is private. + * + * @return bool + */ + public function isPrivate() + { + $phabelReturn = (bool) ($this->flags & Class_::MODIFIER_PRIVATE); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether the method is abstract. + * + * @return bool + */ + public function isAbstract() + { + $phabelReturn = (bool) ($this->flags & Class_::MODIFIER_ABSTRACT); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether the method is final. + * + * @return bool + */ + public function isFinal() + { + $phabelReturn = (bool) ($this->flags & Class_::MODIFIER_FINAL); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether the method is static. + * + * @return bool + */ + public function isStatic() + { + $phabelReturn = (bool) ($this->flags & Class_::MODIFIER_STATIC); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether the method is magic. + * + * @return bool + */ + public function isMagic() + { + $phabelReturn = isset(self::$magicNames[$this->name->toLowerString()]); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_ClassMethod'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Class_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Class_.php new file mode 100644 index 000000000..5af4d74e4 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Class_.php @@ -0,0 +1,137 @@ + 0 : Flags + * 'extends' => null : Name of extended class + * 'implements' => array(): Names of implemented interfaces + * 'stmts' => array(): Statements + * '$attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->flags = isset($subNodes['flags']) ? $subNodes['flags'] : (isset($subNodes['type']) ? $subNodes['type'] : 0); + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->extends = isset($subNodes['extends']) ? $subNodes['extends'] : null; + $this->implements = isset($subNodes['implements']) ? $subNodes['implements'] : []; + $this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : []; + $this->attrGroups = isset($subNodes['attrGroups']) ? $subNodes['attrGroups'] : []; + } + public function getSubNodeNames() + { + $phabelReturn = ['attrGroups', 'flags', 'name', 'extends', 'implements', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Whether the class is explicitly abstract. + * + * @return bool + */ + public function isAbstract() + { + $phabelReturn = (bool) ($this->flags & self::MODIFIER_ABSTRACT); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether the class is final. + * + * @return bool + */ + public function isFinal() + { + $phabelReturn = (bool) ($this->flags & self::MODIFIER_FINAL); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether the class is anonymous. + * + * @return bool + */ + public function isAnonymous() + { + $phabelReturn = null === $this->name; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @internal + */ + public static function verifyModifier($a, $b) + { + if ($a & self::VISIBILITY_MODIFIER_MASK && $b & self::VISIBILITY_MODIFIER_MASK) { + throw new Error('Multiple access type modifiers are not allowed'); + } + if ($a & self::MODIFIER_ABSTRACT && $b & self::MODIFIER_ABSTRACT) { + throw new Error('Multiple abstract modifiers are not allowed'); + } + if ($a & self::MODIFIER_STATIC && $b & self::MODIFIER_STATIC) { + throw new Error('Multiple static modifiers are not allowed'); + } + if ($a & self::MODIFIER_FINAL && $b & self::MODIFIER_FINAL) { + throw new Error('Multiple final modifiers are not allowed'); + } + if ($a & 48 && $b & 48) { + throw new Error('Cannot use the final modifier on an abstract class member'); + } + } + public function getType() + { + $phabelReturn = 'Stmt_Class'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Const_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Const_.php new file mode 100644 index 000000000..6b1103359 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Const_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->consts = $consts; + } + public function getSubNodeNames() + { + $phabelReturn = ['consts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Const'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Continue_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Continue_.php new file mode 100644 index 000000000..11c7218e9 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Continue_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->num = $num; + } + public function getSubNodeNames() + { + $phabelReturn = ['num']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Continue'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php new file mode 100644 index 000000000..b86df222c --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php @@ -0,0 +1,45 @@ +value pair node. + * + * @param string|Node\Identifier $key Key + * @param Node\Expr $value Value + * @param array $attributes Additional attributes + */ + public function __construct($key, Node\Expr $value, array $attributes = []) + { + $this->attributes = $attributes; + $this->key = \is_string($key) ? new Node\Identifier($key) : $key; + $this->value = $value; + } + public function getSubNodeNames() + { + $phabelReturn = ['key', 'value']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_DeclareDeclare'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Declare_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Declare_.php new file mode 100644 index 000000000..555c90fb8 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Declare_.php @@ -0,0 +1,45 @@ +attributes = $attributes; + $this->declares = $declares; + $this->stmts = $stmts; + } + public function getSubNodeNames() + { + $phabelReturn = ['declares', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Declare'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Do_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Do_.php new file mode 100644 index 000000000..e04d4a7ca --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Do_.php @@ -0,0 +1,45 @@ +attributes = $attributes; + $this->cond = $cond; + $this->stmts = $stmts; + } + public function getSubNodeNames() + { + $phabelReturn = ['stmts', 'cond']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Do'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Echo_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Echo_.php new file mode 100644 index 000000000..3f5f97857 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Echo_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->exprs = $exprs; + } + public function getSubNodeNames() + { + $phabelReturn = ['exprs']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Echo'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.php new file mode 100644 index 000000000..0ca5b45b1 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.php @@ -0,0 +1,45 @@ +attributes = $attributes; + $this->cond = $cond; + $this->stmts = $stmts; + } + public function getSubNodeNames() + { + $phabelReturn = ['cond', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_ElseIf'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Else_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Else_.php new file mode 100644 index 000000000..365cef3dc --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Else_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->stmts = $stmts; + } + public function getSubNodeNames() + { + $phabelReturn = ['stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Else'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Expression.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Expression.php new file mode 100644 index 000000000..069178e10 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Expression.php @@ -0,0 +1,44 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Expression'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Finally_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Finally_.php new file mode 100644 index 000000000..87a54a7fe --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Finally_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->stmts = $stmts; + } + public function getSubNodeNames() + { + $phabelReturn = ['stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Finally'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/For_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/For_.php new file mode 100644 index 000000000..0ed34f45a --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/For_.php @@ -0,0 +1,54 @@ + array(): Init expressions + * 'cond' => array(): Loop conditions + * 'loop' => array(): Loop expressions + * 'stmts' => array(): Statements + * @param array $attributes Additional attributes + */ + public function __construct(array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->init = isset($subNodes['init']) ? $subNodes['init'] : []; + $this->cond = isset($subNodes['cond']) ? $subNodes['cond'] : []; + $this->loop = isset($subNodes['loop']) ? $subNodes['loop'] : []; + $this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : []; + } + public function getSubNodeNames() + { + $phabelReturn = ['init', 'cond', 'loop', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_For'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Foreach_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Foreach_.php new file mode 100644 index 000000000..69c75b7eb --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Foreach_.php @@ -0,0 +1,58 @@ + null : Variable to assign key to + * 'byRef' => false : Whether to assign value by reference + * 'stmts' => array(): Statements + * @param array $attributes Additional attributes + */ + public function __construct(Node\Expr $expr, Node\Expr $valueVar, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + $this->keyVar = isset($subNodes['keyVar']) ? $subNodes['keyVar'] : null; + $this->byRef = isset($subNodes['byRef']) ? $subNodes['byRef'] : \false; + $this->valueVar = $valueVar; + $this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : []; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr', 'keyVar', 'byRef', 'valueVar', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Foreach'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Function_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Function_.php new file mode 100644 index 000000000..6de5f8ebd --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Function_.php @@ -0,0 +1,108 @@ + false : Whether to return by reference + * 'params' => array(): Parameters + * 'returnType' => null : Return type + * 'stmts' => array(): Statements + * 'attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->byRef = isset($subNodes['byRef']) ? $subNodes['byRef'] : \false; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->params = isset($subNodes['params']) ? $subNodes['params'] : []; + $returnType = isset($subNodes['returnType']) ? $subNodes['returnType'] : null; + $this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType; + $this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : []; + $this->attrGroups = isset($subNodes['attrGroups']) ? $subNodes['attrGroups'] : []; + } + public function getSubNodeNames() + { + $phabelReturn = ['attrGroups', 'byRef', 'name', 'params', 'returnType', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function returnsByRef() + { + $phabelReturn = $this->byRef; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function getParams() + { + $phabelReturn = $this->params; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getReturnType() + { + return $this->returnType; + } + public function getAttrGroups() + { + $phabelReturn = $this->attrGroups; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** @return Node\Stmt[] */ + public function getStmts() + { + $phabelReturn = $this->stmts; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Function'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Global_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Global_.php new file mode 100644 index 000000000..2a3126589 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Global_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->vars = $vars; + } + public function getSubNodeNames() + { + $phabelReturn = ['vars']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Global'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Goto_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Goto_.php new file mode 100644 index 000000000..143de798c --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Goto_.php @@ -0,0 +1,42 @@ +attributes = $attributes; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames() + { + $phabelReturn = ['name']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Goto'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php new file mode 100644 index 000000000..611937a9d --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php @@ -0,0 +1,57 @@ +attributes = $attributes; + $this->type = $type; + $this->prefix = $prefix; + $this->uses = $uses; + } + public function getSubNodeNames() + { + $phabelReturn = ['type', 'prefix', 'uses']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_GroupUse'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php new file mode 100644 index 000000000..67415dc26 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php @@ -0,0 +1,48 @@ +attributes = $attributes; + $this->remaining = $remaining; + } + public function getSubNodeNames() + { + $phabelReturn = ['remaining']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_HaltCompiler'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/If_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/If_.php new file mode 100644 index 000000000..2b817e2f5 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/If_.php @@ -0,0 +1,54 @@ + array(): Statements + * 'elseifs' => array(): Elseif clauses + * 'else' => null : Else clause + * @param array $attributes Additional attributes + */ + public function __construct(Node\Expr $cond, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->cond = $cond; + $this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : []; + $this->elseifs = isset($subNodes['elseifs']) ? $subNodes['elseifs'] : []; + $this->else = isset($subNodes['else']) ? $subNodes['else'] : null; + } + public function getSubNodeNames() + { + $phabelReturn = ['cond', 'stmts', 'elseifs', 'else']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_If'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.php new file mode 100644 index 000000000..2ee444f73 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.php @@ -0,0 +1,48 @@ +attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames() + { + $phabelReturn = ['value']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_InlineHTML'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Interface_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Interface_.php new file mode 100644 index 000000000..06c7a0c61 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Interface_.php @@ -0,0 +1,48 @@ + array(): Name of extended interfaces + * 'stmts' => array(): Statements + * 'attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->extends = isset($subNodes['extends']) ? $subNodes['extends'] : []; + $this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : []; + $this->attrGroups = isset($subNodes['attrGroups']) ? $subNodes['attrGroups'] : []; + } + public function getSubNodeNames() + { + $phabelReturn = ['attrGroups', 'name', 'extends', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Interface'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Label.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Label.php new file mode 100644 index 000000000..480478fe5 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Label.php @@ -0,0 +1,42 @@ +attributes = $attributes; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames() + { + $phabelReturn = ['name']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Label'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php new file mode 100644 index 000000000..37e7cf8d4 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php @@ -0,0 +1,48 @@ +attributes = $attributes; + $this->name = $name; + $this->stmts = $stmts; + } + public function getSubNodeNames() + { + $phabelReturn = ['name', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Namespace'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Nop.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Nop.php new file mode 100644 index 000000000..886be13f4 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Nop.php @@ -0,0 +1,29 @@ +attributes = $attributes; + $this->flags = $flags; + $this->props = $props; + $this->type = \is_string($type) ? new Identifier($type) : $type; + $this->attrGroups = $attrGroups; + } + public function getSubNodeNames() + { + $phabelReturn = ['attrGroups', 'flags', 'type', 'props']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Whether the property is explicitly or implicitly public. + * + * @return bool + */ + public function isPublic() + { + $phabelReturn = ($this->flags & Class_::MODIFIER_PUBLIC) !== 0 || ($this->flags & Class_::VISIBILITY_MODIFIER_MASK) === 0; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether the property is protected. + * + * @return bool + */ + public function isProtected() + { + $phabelReturn = (bool) ($this->flags & Class_::MODIFIER_PROTECTED); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether the property is private. + * + * @return bool + */ + public function isPrivate() + { + $phabelReturn = (bool) ($this->flags & Class_::MODIFIER_PRIVATE); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Whether the property is static. + * + * @return bool + */ + public function isStatic() + { + $phabelReturn = (bool) ($this->flags & Class_::MODIFIER_STATIC); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Property'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php new file mode 100644 index 000000000..b77b152b0 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php @@ -0,0 +1,45 @@ +attributes = $attributes; + $this->name = \is_string($name) ? new Node\VarLikeIdentifier($name) : $name; + $this->default = $default; + } + public function getSubNodeNames() + { + $phabelReturn = ['name', 'default']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_PropertyProperty'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Return_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Return_.php new file mode 100644 index 000000000..7eafdba59 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Return_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Return'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php new file mode 100644 index 000000000..b344d478b --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php @@ -0,0 +1,46 @@ +attributes = $attributes; + $this->var = $var; + $this->default = $default; + } + public function getSubNodeNames() + { + $phabelReturn = ['var', 'default']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_StaticVar'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Static_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Static_.php new file mode 100644 index 000000000..5e81fe961 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Static_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->vars = $vars; + } + public function getSubNodeNames() + { + $phabelReturn = ['vars']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Static'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Switch_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Switch_.php new file mode 100644 index 000000000..b285c446a --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Switch_.php @@ -0,0 +1,45 @@ +attributes = $attributes; + $this->cond = $cond; + $this->cases = $cases; + } + public function getSubNodeNames() + { + $phabelReturn = ['cond', 'cases']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Switch'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Throw_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Throw_.php new file mode 100644 index 000000000..78dc6080a --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Throw_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() + { + $phabelReturn = ['expr']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Throw'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/TraitUse.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/TraitUse.php new file mode 100644 index 000000000..6ef73f293 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/TraitUse.php @@ -0,0 +1,45 @@ +attributes = $attributes; + $this->traits = $traits; + $this->adaptations = $adaptations; + } + public function getSubNodeNames() + { + $phabelReturn = ['traits', 'adaptations']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_TraitUse'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php new file mode 100644 index 000000000..2d8cdd18d --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php @@ -0,0 +1,12 @@ +attributes = $attributes; + $this->trait = $trait; + $this->method = \is_string($method) ? new Node\Identifier($method) : $method; + $this->newModifier = $newModifier; + $this->newName = \is_string($newName) ? new Node\Identifier($newName) : $newName; + } + public function getSubNodeNames() + { + $phabelReturn = ['trait', 'method', 'newModifier', 'newName']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_TraitUseAdaptation_Alias'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php new file mode 100644 index 000000000..b4dec6a66 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php @@ -0,0 +1,45 @@ +attributes = $attributes; + $this->trait = $trait; + $this->method = \is_string($method) ? new Node\Identifier($method) : $method; + $this->insteadof = $insteadof; + } + public function getSubNodeNames() + { + $phabelReturn = ['trait', 'method', 'insteadof']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_TraitUseAdaptation_Precedence'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Trait_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Trait_.php new file mode 100644 index 000000000..5839ae678 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Trait_.php @@ -0,0 +1,44 @@ + array(): Statements + * 'attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->stmts = isset($subNodes['stmts']) ? $subNodes['stmts'] : []; + $this->attrGroups = isset($subNodes['attrGroups']) ? $subNodes['attrGroups'] : []; + } + public function getSubNodeNames() + { + $phabelReturn = ['attrGroups', 'name', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Trait'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php new file mode 100644 index 000000000..f801d5338 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php @@ -0,0 +1,49 @@ +attributes = $attributes; + $this->stmts = $stmts; + $this->catches = $catches; + $this->finally = $finally; + } + public function getSubNodeNames() + { + $phabelReturn = ['stmts', 'catches', 'finally']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_TryCatch'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Unset_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Unset_.php new file mode 100644 index 000000000..64ef9e052 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Unset_.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->vars = $vars; + } + public function getSubNodeNames() + { + $phabelReturn = ['vars']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Unset'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/UseUse.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/UseUse.php new file mode 100644 index 000000000..498af09de --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/UseUse.php @@ -0,0 +1,77 @@ +attributes = $attributes; + $this->type = $type; + $this->name = $name; + $this->alias = \is_string($alias) ? new Identifier($alias) : $alias; + } + public function getSubNodeNames() + { + $phabelReturn = ['type', 'name', 'alias']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Get alias. If not explicitly given this is the last component of the used name. + * + * @return Identifier + */ + public function getAlias() + { + if (null !== $this->alias) { + $phabelReturn = $this->alias; + if (!$phabelReturn instanceof Identifier) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Identifier, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = new Identifier($this->name->getLast()); + if (!$phabelReturn instanceof Identifier) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Identifier, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_UseUse'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Use_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Use_.php new file mode 100644 index 000000000..d22c5dcff --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/Use_.php @@ -0,0 +1,64 @@ +attributes = $attributes; + $this->type = $type; + $this->uses = $uses; + } + public function getSubNodeNames() + { + $phabelReturn = ['type', 'uses']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_Use'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/While_.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/While_.php new file mode 100644 index 000000000..15ef8e2f6 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/Stmt/While_.php @@ -0,0 +1,45 @@ +attributes = $attributes; + $this->cond = $cond; + $this->stmts = $stmts; + } + public function getSubNodeNames() + { + $phabelReturn = ['cond', 'stmts']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'Stmt_While'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/UnionType.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/UnionType.php new file mode 100644 index 000000000..11fee3f5e --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/UnionType.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->types = $types; + } + public function getSubNodeNames() + { + $phabelReturn = ['types']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getType() + { + $phabelReturn = 'UnionType'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/VarLikeIdentifier.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/VarLikeIdentifier.php new file mode 100644 index 000000000..9ec209db2 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Node/VarLikeIdentifier.php @@ -0,0 +1,26 @@ +attributes = $attributes; + } + /** + * Gets line the node started in (alias of getStartLine). + * + * @return int Start line (or -1 if not available) + */ + public function getLine() + { + $phabelReturn = isset($this->attributes['startLine']) ? $this->attributes['startLine'] : -1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets line the node started in. + * + * Requires the 'startLine' attribute to be enabled in the lexer (enabled by default). + * + * @return int Start line (or -1 if not available) + */ + public function getStartLine() + { + $phabelReturn = isset($this->attributes['startLine']) ? $this->attributes['startLine'] : -1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the line the node ended in. + * + * Requires the 'endLine' attribute to be enabled in the lexer (enabled by default). + * + * @return int End line (or -1 if not available) + */ + public function getEndLine() + { + $phabelReturn = isset($this->attributes['endLine']) ? $this->attributes['endLine'] : -1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the token offset of the first token that is part of this node. + * + * The offset is an index into the array returned by Lexer::getTokens(). + * + * Requires the 'startTokenPos' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int Token start position (or -1 if not available) + */ + public function getStartTokenPos() + { + $phabelReturn = isset($this->attributes['startTokenPos']) ? $this->attributes['startTokenPos'] : -1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the token offset of the last token that is part of this node. + * + * The offset is an index into the array returned by Lexer::getTokens(). + * + * Requires the 'endTokenPos' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int Token end position (or -1 if not available) + */ + public function getEndTokenPos() + { + $phabelReturn = isset($this->attributes['endTokenPos']) ? $this->attributes['endTokenPos'] : -1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the file offset of the first character that is part of this node. + * + * Requires the 'startFilePos' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int File start position (or -1 if not available) + */ + public function getStartFilePos() + { + $phabelReturn = isset($this->attributes['startFilePos']) ? $this->attributes['startFilePos'] : -1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the file offset of the last character that is part of this node. + * + * Requires the 'endFilePos' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int File end position (or -1 if not available) + */ + public function getEndFilePos() + { + $phabelReturn = isset($this->attributes['endFilePos']) ? $this->attributes['endFilePos'] : -1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets all comments directly preceding this node. + * + * The comments are also available through the "comments" attribute. + * + * @return Comment[] + */ + public function getComments() + { + $phabelReturn = isset($this->attributes['comments']) ? $this->attributes['comments'] : []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Gets the doc comment of the node. + * + * @return null|Comment\Doc Doc comment object or null + */ + public function getDocComment() + { + $comments = $this->getComments(); + for ($i = \count($comments) - 1; $i >= 0; $i--) { + $comment = $comments[$i]; + if ($comment instanceof Comment\Doc) { + return $comment; + } + } + return null; + } + /** + * Sets the doc comment of the node. + * + * This will either replace an existing doc comment or add it to the comments array. + * + * @param Comment\Doc $docComment Doc comment to set + */ + public function setDocComment(Comment\Doc $docComment) + { + $comments = $this->getComments(); + for ($i = \count($comments) - 1; $i >= 0; $i--) { + if ($comments[$i] instanceof Comment\Doc) { + // Replace existing doc comment. + $comments[$i] = $docComment; + $this->setAttribute('comments', $comments); + return; + } + } + // Append new doc comment. + $comments[] = $docComment; + $this->setAttribute('comments', $comments); + } + public function setAttribute($key, $value) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + $this->attributes[$key] = $value; + } + public function hasAttribute($key) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + $phabelReturn = \array_key_exists($key, $this->attributes); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function getAttribute($key, $default = null) + { + if (!\is_string($key)) { + if (!(\is_string($key) || \is_object($key) && \method_exists($key, '__toString') || (\is_bool($key) || \is_numeric($key)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($key) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($key) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $key = (string) $key; + } + } + if (\array_key_exists($key, $this->attributes)) { + return $this->attributes[$key]; + } + return $default; + } + public function getAttributes() + { + $phabelReturn = $this->attributes; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function setAttributes(array $attributes) + { + $this->attributes = $attributes; + } + /** + * @return array + */ + public function jsonSerialize() + { + $phabelReturn = ['nodeType' => $this->getType()] + \get_object_vars($this); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeDumper.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeDumper.php new file mode 100644 index 000000000..06bf8d79d --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeDumper.php @@ -0,0 +1,194 @@ +dumpComments = !empty($options['dumpComments']); + $this->dumpPositions = !empty($options['dumpPositions']); + } + /** + * Dumps a node or array. + * + * @param array|Node $node Node or array to dump + * @param string|null $code Code corresponding to dumped AST. This only needs to be passed if + * the dumpPositions option is enabled and the dumping of node offsets + * is desired. + * + * @return string Dumped value + */ + public function dump($node, $code = null) + { + if (!\is_null($code)) { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($code) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + } + $this->code = $code; + $phabelReturn = $this->dumpRecursive($node); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + protected function dumpRecursive($node) + { + if ($node instanceof Node) { + $r = $node->getType(); + if ($this->dumpPositions && null !== ($p = $this->dumpPosition($node))) { + $r .= $p; + } + $r .= '('; + foreach ($node->getSubNodeNames() as $key) { + $r .= "\n " . $key . ': '; + $value = $node->{$key}; + if (null === $value) { + $r .= 'null'; + } elseif (\false === $value) { + $r .= 'false'; + } elseif (\true === $value) { + $r .= 'true'; + } elseif (\is_scalar($value)) { + if ('flags' === $key || 'newModifier' === $key) { + $r .= $this->dumpFlags($value); + } elseif ('type' === $key && $node instanceof Include_) { + $r .= $this->dumpIncludeType($value); + } elseif ('type' === $key && ($node instanceof Use_ || $node instanceof UseUse || $node instanceof GroupUse)) { + $r .= $this->dumpUseType($value); + } else { + $r .= $value; + } + } else { + $r .= \str_replace("\n", "\n ", $this->dumpRecursive($value)); + } + } + if ($this->dumpComments && ($comments = $node->getComments())) { + $r .= "\n comments: " . \str_replace("\n", "\n ", $this->dumpRecursive($comments)); + } + } elseif (\is_array($node)) { + $r = 'array('; + foreach ($node as $key => $value) { + $r .= "\n " . $key . ': '; + if (null === $value) { + $r .= 'null'; + } elseif (\false === $value) { + $r .= 'false'; + } elseif (\true === $value) { + $r .= 'true'; + } elseif (\is_scalar($value)) { + $r .= $value; + } else { + $r .= \str_replace("\n", "\n ", $this->dumpRecursive($value)); + } + } + } elseif ($node instanceof Comment) { + return $node->getReformattedText(); + } else { + throw new \InvalidArgumentException('Can only dump nodes and arrays.'); + } + return $r . "\n)"; + } + protected function dumpFlags($flags) + { + $strs = []; + if ($flags & Class_::MODIFIER_PUBLIC) { + $strs[] = 'MODIFIER_PUBLIC'; + } + if ($flags & Class_::MODIFIER_PROTECTED) { + $strs[] = 'MODIFIER_PROTECTED'; + } + if ($flags & Class_::MODIFIER_PRIVATE) { + $strs[] = 'MODIFIER_PRIVATE'; + } + if ($flags & Class_::MODIFIER_ABSTRACT) { + $strs[] = 'MODIFIER_ABSTRACT'; + } + if ($flags & Class_::MODIFIER_STATIC) { + $strs[] = 'MODIFIER_STATIC'; + } + if ($flags & Class_::MODIFIER_FINAL) { + $strs[] = 'MODIFIER_FINAL'; + } + if ($strs) { + return \implode(' | ', $strs) . ' (' . $flags . ')'; + } else { + return $flags; + } + } + protected function dumpIncludeType($type) + { + $map = [Include_::TYPE_INCLUDE => 'TYPE_INCLUDE', Include_::TYPE_INCLUDE_ONCE => 'TYPE_INCLUDE_ONCE', Include_::TYPE_REQUIRE => 'TYPE_REQUIRE', Include_::TYPE_REQUIRE_ONCE => 'TYPE_REQUIRE_ONCE']; + if (!isset($map[$type])) { + return $type; + } + return $map[$type] . ' (' . $type . ')'; + } + protected function dumpUseType($type) + { + $map = [Use_::TYPE_UNKNOWN => 'TYPE_UNKNOWN', Use_::TYPE_NORMAL => 'TYPE_NORMAL', Use_::TYPE_FUNCTION => 'TYPE_FUNCTION', Use_::TYPE_CONSTANT => 'TYPE_CONSTANT']; + if (!isset($map[$type])) { + return $type; + } + return $map[$type] . ' (' . $type . ')'; + } + /** + * Dump node position, if possible. + * + * @param Node $node Node for which to dump position + * + * @return string|null Dump of position, or null if position information not available + */ + protected function dumpPosition(Node $node) + { + if (!$node->hasAttribute('startLine') || !$node->hasAttribute('endLine')) { + return null; + } + $start = $node->getStartLine(); + $end = $node->getEndLine(); + if ($node->hasAttribute('startFilePos') && $node->hasAttribute('endFilePos') && null !== $this->code) { + $start .= ':' . $this->toColumn($this->code, $node->getStartFilePos()); + $end .= ':' . $this->toColumn($this->code, $node->getEndFilePos()); + } + return "[{$start} - {$end}]"; + } + // Copied from Error class + private function toColumn($code, $pos) + { + if ($pos > \strlen($code)) { + throw new \RuntimeException('Invalid position information'); + } + $lineStartPos = \strrpos($code, "\n", $pos - \strlen($code)); + if (\false === $lineStartPos) { + $lineStartPos = -1; + } + return $pos - $lineStartPos; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeFinder.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeFinder.php new file mode 100644 index 000000000..72eb28609 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeFinder.php @@ -0,0 +1,97 @@ +addVisitor($visitor); + $traverser->traverse($nodes); + $phabelReturn = $visitor->getFoundNodes(); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Find all nodes that are instances of a certain class. + * + * @param Node|Node[] $nodes Single node or array of nodes to search in + * @param string $class Class name + * + * @return Node[] Found nodes (all instances of $class) + */ + public function findInstanceOf($nodes, $class) + { + if (!\is_string($class)) { + if (!(\is_string($class) || \is_object($class) && \method_exists($class, '__toString') || (\is_bool($class) || \is_numeric($class)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($class) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($class) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $class = (string) $class; + } + } + $phabelReturn = $this->find($nodes, function ($node) use($class) { + return \Phabel\Target\Php70\ThrowableReplacer::isInstanceofThrowable($node, $class); + }); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Find first node satisfying a filter callback. + * + * @param Node|Node[] $nodes Single node or array of nodes to search in + * @param callable $filter Filter callback: function(Node $node) : bool + * + * @return null|Node Found node (or null if none found) + */ + public function findFirst($nodes, callable $filter) + { + if (!\is_array($nodes)) { + $nodes = [$nodes]; + } + $visitor = new FirstFindingVisitor($filter); + $traverser = new NodeTraverser(); + $traverser->addVisitor($visitor); + $traverser->traverse($nodes); + return $visitor->getFoundNode(); + } + /** + * Find first node that is an instance of a certain class. + * + * @param Node|Node[] $nodes Single node or array of nodes to search in + * @param string $class Class name + * + * @return null|Node Found node, which is an instance of $class (or null if none found) + */ + public function findFirstInstanceOf($nodes, $class) + { + if (!\is_string($class)) { + if (!(\is_string($class) || \is_object($class) && \method_exists($class, '__toString') || (\is_bool($class) || \is_numeric($class)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($class) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($class) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $class = (string) $class; + } + } + return $this->findFirst($nodes, function ($node) use($class) { + return \Phabel\Target\Php70\ThrowableReplacer::isInstanceofThrowable($node, $class); + }); + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeTraverser.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeTraverser.php new file mode 100644 index 000000000..418c82034 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeTraverser.php @@ -0,0 +1,257 @@ +visitors[] = $visitor; + } + /** + * Removes an added visitor. + * + * @param NodeVisitor $visitor + */ + public function removeVisitor(NodeVisitor $visitor) + { + foreach ($this->visitors as $index => $storedVisitor) { + if ($storedVisitor === $visitor) { + unset($this->visitors[$index]); + break; + } + } + } + /** + * Traverses an array of nodes using the registered visitors. + * + * @param Node[] $nodes Array of nodes + * + * @return Node[] Traversed array of nodes + */ + public function traverse(array $nodes) + { + $this->stopTraversal = \false; + foreach ($this->visitors as $visitor) { + if (null !== ($return = $visitor->beforeTraverse($nodes))) { + $nodes = $return; + } + } + $nodes = $this->traverseArray($nodes); + foreach ($this->visitors as $visitor) { + if (null !== ($return = $visitor->afterTraverse($nodes))) { + $nodes = $return; + } + } + $phabelReturn = $nodes; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Recursively traverse a node. + * + * @param Node $node Node to traverse. + * + * @return Node Result of traversal (may be original node or new one) + */ + protected function traverseNode(Node $node) + { + foreach ($node->getSubNodeNames() as $name) { + $subNode =& $node->{$name}; + if (\is_array($subNode)) { + $subNode = $this->traverseArray($subNode); + if ($this->stopTraversal) { + break; + } + } elseif ($subNode instanceof Node) { + $traverseChildren = \true; + $breakVisitorIndex = null; + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->enterNode($subNode); + if (null !== $return) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($subNode, $return); + $subNode = $return; + } elseif (self::DONT_TRAVERSE_CHILDREN === $return) { + $traverseChildren = \false; + } elseif (self::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) { + $traverseChildren = \false; + $breakVisitorIndex = $visitorIndex; + break; + } elseif (self::STOP_TRAVERSAL === $return) { + $this->stopTraversal = \true; + break 2; + } else { + throw new \LogicException('enterNode() returned invalid value of type ' . \gettype($return)); + } + } + } + if ($traverseChildren) { + $subNode = $this->traverseNode($subNode); + if ($this->stopTraversal) { + break; + } + } + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->leaveNode($subNode); + if (null !== $return) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($subNode, $return); + $subNode = $return; + } elseif (self::STOP_TRAVERSAL === $return) { + $this->stopTraversal = \true; + break 2; + } elseif (\is_array($return)) { + throw new \LogicException('leaveNode() may only return an array if the parent structure is an array'); + } else { + throw new \LogicException('leaveNode() returned invalid value of type ' . \gettype($return)); + } + } + if ($breakVisitorIndex === $visitorIndex) { + break; + } + } + } + } + $phabelReturn = $node; + if (!$phabelReturn instanceof Node) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Node, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Recursively traverse array (usually of nodes). + * + * @param array $nodes Array to traverse + * + * @return array Result of traversal (may be original array or changed one) + */ + protected function traverseArray(array $nodes) + { + $doNodes = []; + foreach ($nodes as $i => &$node) { + if ($node instanceof Node) { + $traverseChildren = \true; + $breakVisitorIndex = null; + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->enterNode($node); + if (null !== $return) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($node, $return); + $node = $return; + } elseif (self::DONT_TRAVERSE_CHILDREN === $return) { + $traverseChildren = \false; + } elseif (self::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) { + $traverseChildren = \false; + $breakVisitorIndex = $visitorIndex; + break; + } elseif (self::STOP_TRAVERSAL === $return) { + $this->stopTraversal = \true; + break 2; + } else { + throw new \LogicException('enterNode() returned invalid value of type ' . \gettype($return)); + } + } + } + if ($traverseChildren) { + $node = $this->traverseNode($node); + if ($this->stopTraversal) { + break; + } + } + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->leaveNode($node); + if (null !== $return) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($node, $return); + $node = $return; + } elseif (\is_array($return)) { + $doNodes[] = [$i, $return]; + break; + } elseif (self::REMOVE_NODE === $return) { + $doNodes[] = [$i, []]; + break; + } elseif (self::STOP_TRAVERSAL === $return) { + $this->stopTraversal = \true; + break 2; + } elseif (\false === $return) { + throw new \LogicException('bool(false) return from leaveNode() no longer supported. Return NodeTraverser::REMOVE_NODE instead'); + } else { + throw new \LogicException('leaveNode() returned invalid value of type ' . \gettype($return)); + } + } + if ($breakVisitorIndex === $visitorIndex) { + break; + } + } + } elseif (\is_array($node)) { + throw new \LogicException('Invalid node structure: Contains nested arrays'); + } + } + if (!empty($doNodes)) { + while (list($i, $replace) = \array_pop($doNodes)) { + \array_splice($nodes, $i, 1, $replace); + } + } + $phabelReturn = $nodes; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function ensureReplacementReasonable($old, $new) + { + if ($old instanceof Node\Stmt && $new instanceof Node\Expr) { + throw new \LogicException("Trying to replace statement ({$old->getType()}) " . "with expression ({$new->getType()}). Are you missing a " . "Stmt_Expression wrapper?"); + } + if ($old instanceof Node\Expr && $new instanceof Node\Stmt) { + throw new \LogicException("Trying to replace expression ({$old->getType()}) " . "with statement ({$new->getType()})"); + } + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeTraverserInterface.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeTraverserInterface.php new file mode 100644 index 000000000..6edc46ecd --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeTraverserInterface.php @@ -0,0 +1,27 @@ + $node stays as-is + * * NodeTraverser::DONT_TRAVERSE_CHILDREN + * => Children of $node are not traversed. $node stays as-is + * * NodeTraverser::STOP_TRAVERSAL + * => Traversal is aborted. $node stays as-is + * * otherwise + * => $node is set to the return value + * + * @param Node $node Node + * + * @return null|int|Node Replacement node (or special return value) + */ + public function enterNode(Node $node); + /** + * Called when leaving a node. + * + * Return value semantics: + * * null + * => $node stays as-is + * * NodeTraverser::REMOVE_NODE + * => $node is removed from the parent array + * * NodeTraverser::STOP_TRAVERSAL + * => Traversal is aborted. $node stays as-is + * * array (of Nodes) + * => The return value is merged into the parent array (at the position of the $node) + * * otherwise + * => $node is set to the return value + * + * @param Node $node Node + * + * @return null|int|Node|Node[] Replacement node (or special return value) + */ + public function leaveNode(Node $node); + /** + * Called once after traversal. + * + * Return value semantics: + * * null: $nodes stays as-is + * * otherwise: $nodes is set to the return value + * + * @param Node[] $nodes Array of nodes + * + * @return null|Node[] Array of nodes + */ + public function afterTraverse(array $nodes); +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php new file mode 100644 index 000000000..f9617af13 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php @@ -0,0 +1,20 @@ +setAttribute('origNode', $origNode); + return $node; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php new file mode 100644 index 000000000..d4cd39322 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php @@ -0,0 +1,49 @@ +filterCallback = $filterCallback; + } + /** + * Get found nodes satisfying the filter callback. + * + * Nodes are returned in pre-order. + * + * @return Node[] Found nodes + */ + public function getFoundNodes() + { + $phabelReturn = $this->foundNodes; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function beforeTraverse(array $nodes) + { + $this->foundNodes = []; + return null; + } + public function enterNode(Node $node) + { + $filterCallback = $this->filterCallback; + if ($filterCallback($node)) { + $this->foundNodes[] = $node; + } + return null; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php new file mode 100644 index 000000000..ac903c34f --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php @@ -0,0 +1,47 @@ +filterCallback = $filterCallback; + } + /** + * Get found node satisfying the filter callback. + * + * Returns null if no node satisfies the filter callback. + * + * @return null|Node Found node (or null if not found) + */ + public function getFoundNode() + { + return $this->foundNode; + } + public function beforeTraverse(array $nodes) + { + $this->foundNode = null; + return null; + } + public function enterNode(Node $node) + { + $filterCallback = $this->filterCallback; + if ($filterCallback($node)) { + $this->foundNode = $node; + return NodeTraverser::STOP_TRAVERSAL; + } + return null; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php new file mode 100644 index 000000000..a817ab828 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php @@ -0,0 +1,244 @@ +nameContext = new NameContext(isset($errorHandler) ? $errorHandler : new ErrorHandler\Throwing()); + $this->preserveOriginalNames = isset($options['preserveOriginalNames']) ? $options['preserveOriginalNames'] : \false; + $this->replaceNodes = isset($options['replaceNodes']) ? $options['replaceNodes'] : \true; + } + /** + * Get name resolution context. + * + * @return NameContext + */ + public function getNameContext() + { + $phabelReturn = $this->nameContext; + if (!$phabelReturn instanceof NameContext) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type NameContext, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function beforeTraverse(array $nodes) + { + $this->nameContext->startNamespace(); + return null; + } + public function enterNode(Node $node) + { + if ($node instanceof Stmt\Namespace_) { + $this->nameContext->startNamespace($node->name); + } elseif ($node instanceof Stmt\Use_) { + foreach ($node->uses as $use) { + $this->addAlias($use, $node->type, null); + } + } elseif ($node instanceof Stmt\GroupUse) { + foreach ($node->uses as $use) { + $this->addAlias($use, $node->type, $node->prefix); + } + } elseif ($node instanceof Stmt\Class_) { + if (null !== $node->extends) { + $node->extends = $this->resolveClassName($node->extends); + } + foreach ($node->implements as &$interface) { + $interface = $this->resolveClassName($interface); + } + $this->resolveAttrGroups($node); + if (null !== $node->name) { + $this->addNamespacedName($node); + } + } elseif ($node instanceof Stmt\Interface_) { + foreach ($node->extends as &$interface) { + $interface = $this->resolveClassName($interface); + } + $this->resolveAttrGroups($node); + $this->addNamespacedName($node); + } elseif ($node instanceof Stmt\Trait_) { + $this->resolveAttrGroups($node); + $this->addNamespacedName($node); + } elseif ($node instanceof Stmt\Function_) { + $this->resolveSignature($node); + $this->resolveAttrGroups($node); + $this->addNamespacedName($node); + } elseif ($node instanceof Stmt\ClassMethod || $node instanceof Expr\Closure || $node instanceof Expr\ArrowFunction) { + $this->resolveSignature($node); + $this->resolveAttrGroups($node); + } elseif ($node instanceof Stmt\Property) { + if (null !== $node->type) { + $node->type = $this->resolveType($node->type); + } + $this->resolveAttrGroups($node); + } elseif ($node instanceof Stmt\Const_) { + foreach ($node->consts as $const) { + $this->addNamespacedName($const); + } + } else { + if ($node instanceof Stmt\ClassConst) { + $this->resolveAttrGroups($node); + } elseif ($node instanceof Expr\StaticCall || $node instanceof Expr\StaticPropertyFetch || $node instanceof Expr\ClassConstFetch || $node instanceof Expr\New_ || $node instanceof Expr\Instanceof_) { + if ($node->class instanceof Name) { + $node->class = $this->resolveClassName($node->class); + } + } elseif ($node instanceof Stmt\Catch_) { + foreach ($node->types as &$type) { + $type = $this->resolveClassName($type); + } + } elseif ($node instanceof Expr\FuncCall) { + if ($node->name instanceof Name) { + $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_FUNCTION); + } + } elseif ($node instanceof Expr\ConstFetch) { + $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_CONSTANT); + } elseif ($node instanceof Stmt\TraitUse) { + foreach ($node->traits as &$trait) { + $trait = $this->resolveClassName($trait); + } + foreach ($node->adaptations as $adaptation) { + if (null !== $adaptation->trait) { + $adaptation->trait = $this->resolveClassName($adaptation->trait); + } + if ($adaptation instanceof Stmt\TraitUseAdaptation\Precedence) { + foreach ($adaptation->insteadof as &$insteadof) { + $insteadof = $this->resolveClassName($insteadof); + } + } + } + } + } + return null; + } + private function addAlias(Stmt\UseUse $use, $type, Name $prefix = null) + { + // Add prefix for group uses + $name = $prefix ? Name::concat($prefix, $use->name) : $use->name; + // Type is determined either by individual element or whole use declaration + $type |= $use->type; + $this->nameContext->addAlias($name, (string) $use->getAlias(), $type, $use->getAttributes()); + } + /** @param Stmt\Function_|Stmt\ClassMethod|Expr\Closure $node */ + private function resolveSignature($node) + { + foreach ($node->params as $param) { + $param->type = $this->resolveType($param->type); + $this->resolveAttrGroups($param); + } + $node->returnType = $this->resolveType($node->returnType); + } + private function resolveType($node) + { + if ($node instanceof Name) { + return $this->resolveClassName($node); + } + if ($node instanceof Node\NullableType) { + $node->type = $this->resolveType($node->type); + return $node; + } + if ($node instanceof Node\UnionType) { + foreach ($node->types as &$type) { + $type = $this->resolveType($type); + } + return $node; + } + return $node; + } + /** + * Resolve name, according to name resolver options. + * + * @param Name $name Function or constant name to resolve + * @param int $type One of Stmt\Use_::TYPE_* + * + * @return Name Resolved name, or original name with attribute + */ + protected function resolveName(Name $name, $type) + { + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + if (!$this->replaceNodes) { + $resolvedName = $this->nameContext->getResolvedName($name, $type); + if (null !== $resolvedName) { + $name->setAttribute('resolvedName', $resolvedName); + } else { + $name->setAttribute('namespacedName', FullyQualified::concat($this->nameContext->getNamespace(), $name, $name->getAttributes())); + } + $phabelReturn = $name; + if (!$phabelReturn instanceof Name) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Name, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->preserveOriginalNames) { + // Save the original name + $originalName = $name; + $name = clone $originalName; + $name->setAttribute('originalName', $originalName); + } + $resolvedName = $this->nameContext->getResolvedName($name, $type); + if (null !== $resolvedName) { + $phabelReturn = $resolvedName; + if (!$phabelReturn instanceof Name) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Name, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + // unqualified names inside a namespace cannot be resolved at compile-time + // add the namespaced version of the name as an attribute + $name->setAttribute('namespacedName', FullyQualified::concat($this->nameContext->getNamespace(), $name, $name->getAttributes())); + $phabelReturn = $name; + if (!$phabelReturn instanceof Name) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Name, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + protected function resolveClassName(Name $name) + { + return $this->resolveName($name, Stmt\Use_::TYPE_NORMAL); + } + protected function addNamespacedName(Node $node) + { + $node->namespacedName = Name::concat($this->nameContext->getNamespace(), (string) $node->name); + } + protected function resolveAttrGroups(Node $node) + { + foreach ($node->attrGroups as $attrGroup) { + foreach ($attrGroup->attrs as $attr) { + $attr->name = $this->resolveClassName($attr->name); + } + } + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.php new file mode 100644 index 000000000..b7159c4e9 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.php @@ -0,0 +1,47 @@ +$node->getAttribute('parent'), the previous + * node can be accessed through $node->getAttribute('previous'), + * and the next node can be accessed through $node->getAttribute('next'). + */ +final class NodeConnectingVisitor extends NodeVisitorAbstract +{ + /** + * @var Node[] + */ + private $stack = []; + /** + * @var ?Node + */ + private $previous; + public function beforeTraverse(array $nodes) + { + $this->stack = []; + $this->previous = null; + } + public function enterNode(Node $node) + { + if (!empty($this->stack)) { + $node->setAttribute('parent', $this->stack[\count($this->stack) - 1]); + } + if ($this->previous !== null && $this->previous->getAttribute('parent') === $node->getAttribute('parent')) { + $node->setAttribute('previous', $this->previous); + $this->previous->setAttribute('next', $node); + } + $this->stack[] = $node; + } + public function leaveNode(Node $node) + { + $this->previous = $node; + \array_pop($this->stack); + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php new file mode 100644 index 000000000..017d3519f --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php @@ -0,0 +1,36 @@ +$node->getAttribute('parent'). + */ +final class ParentConnectingVisitor extends NodeVisitorAbstract +{ + /** + * @var Node[] + */ + private $stack = []; + public function beforeTraverse(array $nodes) + { + $this->stack = []; + } + public function enterNode(Node $node) + { + if (!empty($this->stack)) { + $node->setAttribute('parent', $this->stack[count($this->stack) - 1]); + } + $this->stack[] = $node; + } + public function leaveNode(Node $node) + { + array_pop($this->stack); + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitorAbstract.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitorAbstract.php new file mode 100644 index 000000000..0d596a39b --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/NodeVisitorAbstract.php @@ -0,0 +1,26 @@ +parsers = $parsers; + } + public function parse($code, ErrorHandler $errorHandler = null) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + if (null === $errorHandler) { + $errorHandler = new ErrorHandler\Throwing(); + } + list($firstStmts, $firstError) = $this->tryParse($this->parsers[0], $errorHandler, $code); + if ($firstError === null) { + return $firstStmts; + } + for ($i = 1, $c = \count($this->parsers); $i < $c; ++$i) { + list($stmts, $error) = $this->tryParse($this->parsers[$i], $errorHandler, $code); + if ($error === null) { + return $stmts; + } + } + throw $firstError; + } + private function tryParse(Parser $parser, ErrorHandler $errorHandler, $code) + { + $stmts = null; + $error = null; + try { + $stmts = $parser->parse($code, $errorHandler); + } catch (Error $error) { + } + return [$stmts, $error]; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Parser/Php5.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Parser/Php5.php new file mode 100644 index 000000000..2c1e25b61 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Parser/Php5.php @@ -0,0 +1,1302 @@ +'", "T_IS_GREATER_OR_EQUAL", "T_SL", "T_SR", "'+'", "'-'", "'.'", "'*'", "'/'", "'%'", "'!'", "T_INSTANCEOF", "'~'", "T_INC", "T_DEC", "T_INT_CAST", "T_DOUBLE_CAST", "T_STRING_CAST", "T_ARRAY_CAST", "T_OBJECT_CAST", "T_BOOL_CAST", "T_UNSET_CAST", "'@'", "T_POW", "'['", "T_NEW", "T_CLONE", "T_EXIT", "T_IF", "T_ELSEIF", "T_ELSE", "T_ENDIF", "T_LNUMBER", "T_DNUMBER", "T_STRING", "T_STRING_VARNAME", "T_VARIABLE", "T_NUM_STRING", "T_INLINE_HTML", "T_ENCAPSED_AND_WHITESPACE", "T_CONSTANT_ENCAPSED_STRING", "T_ECHO", "T_DO", "T_WHILE", "T_ENDWHILE", "T_FOR", "T_ENDFOR", "T_FOREACH", "T_ENDFOREACH", "T_DECLARE", "T_ENDDECLARE", "T_AS", "T_SWITCH", "T_MATCH", "T_ENDSWITCH", "T_CASE", "T_DEFAULT", "T_BREAK", "T_CONTINUE", "T_GOTO", "T_FUNCTION", "T_FN", "T_CONST", "T_RETURN", "T_TRY", "T_CATCH", "T_FINALLY", "T_USE", "T_INSTEADOF", "T_GLOBAL", "T_STATIC", "T_ABSTRACT", "T_FINAL", "T_PRIVATE", "T_PROTECTED", "T_PUBLIC", "T_VAR", "T_UNSET", "T_ISSET", "T_EMPTY", "T_HALT_COMPILER", "T_CLASS", "T_TRAIT", "T_INTERFACE", "T_EXTENDS", "T_IMPLEMENTS", "T_OBJECT_OPERATOR", "T_LIST", "T_ARRAY", "T_CALLABLE", "T_CLASS_C", "T_TRAIT_C", "T_METHOD_C", "T_FUNC_C", "T_LINE", "T_FILE", "T_START_HEREDOC", "T_END_HEREDOC", "T_DOLLAR_OPEN_CURLY_BRACES", "T_CURLY_OPEN", "T_PAAMAYIM_NEKUDOTAYIM", "T_NAMESPACE", "T_NS_C", "T_DIR", "T_NS_SEPARATOR", "T_ELLIPSIS", "T_NAME_FULLY_QUALIFIED", "T_NAME_QUALIFIED", "T_NAME_RELATIVE", "';'", "'{'", "'}'", "'('", "')'", "'\$'", "'`'", "']'", "'\"'", "T_NULLSAFE_OBJECT_OPERATOR", "T_ATTRIBUTE"); + protected $tokenToSymbol = array(0, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 55, 162, 165, 159, 54, 37, 165, 157, 158, 52, 49, 8, 50, 51, 53, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 31, 154, 43, 16, 45, 30, 67, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 69, 165, 161, 36, 165, 160, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 155, 35, 156, 57, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 38, 39, 40, 41, 42, 44, 46, 47, 48, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 163, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 164); + protected $action = array(693, 663, 664, 665, 666, 667, 282, 668, 669, 670, 706, 707, 221, 222, 223, 224, 225, 226, 227, 228, 229, 0, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, 27, 242, 243, -32766, -32766, -32766, -32766, -32766, 671, -32766, 333, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, -32767, 672, 673, 674, 675, 676, 677, 678, 1034, 816, 740, 941, 942, 943, 940, 939, 938, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 709, 732, 710, 711, 712, 713, 701, 702, 703, 731, 704, 705, 690, 691, 692, 694, 695, 696, 734, 735, 736, 737, 738, 739, 697, 698, 699, 700, 730, 721, 719, 720, 716, 717, 437, 708, 714, 715, 722, 723, 725, 724, 726, 727, 55, 56, 417, 57, 58, 718, 729, 728, 28, 59, 60, -220, 61, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 36, -32767, -32767, -32767, -32767, 1034, 35, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, -32766, -32766, -32766, -32766, 62, 63, 1034, 125, 285, 292, 64, 748, 65, 290, 291, 66, 67, 68, 69, 70, 71, 72, 73, 763, 25, 298, 74, 409, 973, 975, 294, 294, 1086, 1087, 1064, 796, 748, 218, 219, 220, 465, -32766, -32766, -32766, 742, 864, 817, 54, 807, 9, -32766, -32766, -32766, 760, 320, 761, 410, 10, 202, 246, 428, 209, -32766, 933, -32766, -32766, -32766, -32766, -32766, -32766, 488, -32766, 438, -32766, -32766, -32766, -32766, -32766, 473, 474, 941, 942, 943, 940, 939, 938, -32766, 475, 476, 337, 1092, 1093, 1094, 1095, 1089, 1090, 315, 1214, -255, 747, 1215, -505, 1096, 1091, 888, 889, 1066, 1065, 1067, 218, 219, 220, 41, 414, 337, 330, 895, 332, 418, -126, -126, -126, 75, 52, 464, -4, 817, 54, 805, -224, 202, 40, 21, 419, -126, 466, -126, 467, -126, 468, -126, 359, 420, 128, 128, 748, 1171, 31, 32, 421, 422, 1034, 894, 33, 469, -32766, -32766, -32766, 1186, 351, 352, 470, 471, -32766, -32766, -32766, 309, 472, 865, 323, 788, 835, 423, 424, -32767, -32767, -32767, -32767, 97, 98, 99, 100, 101, 615, -32766, 313, -32766, -32766, -32766, -32766, 354, 1185, 1171, 218, 219, 220, 475, 748, 418, 819, 629, -126, 297, 915, 464, 817, 54, -32766, 805, 124, 748, 40, 21, 419, 202, 466, 48, 467, 534, 468, 129, 429, 420, 337, 341, 888, 889, 31, 32, 421, 422, 416, 405, 33, 469, -32766, -32766, 311, 298, 351, 352, 470, 471, -32766, -32766, -32766, 748, 472, 412, 748, 752, 835, 423, 424, 338, 1066, 1065, 1067, 219, 220, 919, 1136, 296, 20, -32766, 576, -32766, -32766, -32766, 742, 341, 342, 413, 429, 1064, 337, 512, 418, 202, 819, 629, -4, 1034, 464, 817, 54, 49, 805, 337, 762, 40, 21, 419, 51, 466, 1034, 467, 475, 468, 340, 748, 420, 120, -205, -205, -205, 31, 32, 421, 422, 1062, -32766, 33, 469, -32766, -32766, -32766, 744, 351, 352, 470, 471, 429, 1098, 337, 429, 472, 337, 1034, 788, 835, 423, 424, 415, 1098, -32766, 802, -32766, -32766, 102, 103, 104, 1137, 303, 202, 130, 1066, 1065, 1067, 337, 123, 239, 240, 241, 748, 105, 418, 1205, 819, 629, -205, 440, 464, -32766, -32766, -32766, 805, 242, 243, 40, 21, 419, 121, 466, 126, 467, 429, 468, 337, 122, 420, 1052, -204, -204, -204, 31, 32, 421, 422, 1034, 745, 33, 469, 220, 759, 817, 54, 351, 352, 470, 471, 218, 219, 220, 119, 472, 244, 127, 788, 835, 423, 424, 202, -32766, -32766, -32766, 30, 293, 803, 79, 80, 81, 202, 798, 210, 632, 99, 100, 101, 236, 237, 238, 817, 54, -32766, 211, 800, 819, 629, -204, 34, 1034, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 286, 303, 418, 1034, 817, 54, -32766, -32766, 464, 218, 219, 220, 805, 105, 914, 40, 21, 419, 78, 466, 212, 467, 337, 468, 133, 247, 420, 295, 567, 248, 202, 31, 32, 421, 633, 242, 243, 33, 469, 418, 249, 817, 54, 351, 352, 464, 760, -84, 761, 805, 310, 472, 40, 21, 419, -32766, 466, 640, 467, 643, 468, 447, 22, 420, 815, 452, 584, 132, 31, 32, 421, 637, 134, 364, 33, 469, 418, 303, 817, 54, 351, 352, 464, 819, 629, 828, 805, 43, 472, 40, 21, 419, 44, 466, 45, 467, 46, 468, 591, 592, 420, 753, 635, 930, 649, 31, 32, 421, 641, 918, 657, 33, 469, 418, 105, 817, 54, 351, 352, 464, 819, 629, 47, 805, 50, 472, 40, 21, 419, 53, 466, 131, 467, 298, 468, 599, 742, 420, -32766, -274, 516, 570, 31, 32, 421, 646, 748, 946, 33, 469, 418, 589, 436, -32766, 351, 352, 464, 819, 629, 623, 805, 836, 472, 40, 21, 419, 611, 466, -82, 467, 603, 468, 11, 573, 420, 439, 456, 281, 318, 31, 32, 421, 588, 432, 321, 33, 469, 418, -414, 458, 322, 351, 352, 464, 851, 629, 837, 805, -505, 472, 40, 21, 419, 654, 466, 38, 467, 24, 468, 0, 0, 420, 319, 0, -405, 0, 31, 32, 421, 245, 312, 314, 33, 469, -506, 0, 0, 1097, 351, 352, 1143, 819, 629, 0, 0, 527, 472, 213, 214, 6, 7, 12, 14, 215, 363, 216, -415, 558, 789, -221, 830, 0, 0, 747, 0, 0, 0, 207, 39, 652, 653, 758, 806, 814, 793, 1086, 1087, 808, 819, 629, 213, 214, 867, 1088, 858, 859, 215, 791, 216, 852, 849, 847, 925, 926, 923, 813, 797, 799, 801, 804, 207, 922, 756, 757, 924, 287, 78, 331, 1086, 1087, 353, 630, 634, 636, 638, 639, 1088, 642, 644, 645, 647, 648, 631, 1142, 1211, 1213, 755, 834, 754, 833, 1212, 554, 832, 1092, 1093, 1094, 1095, 1089, 1090, 388, 1048, 824, 1036, 831, 1037, 1096, 1091, 822, 931, 856, 857, 451, 1210, 1179, 0, 217, 1177, 1162, 1175, 1077, 906, 1183, 1173, 0, 554, 26, 1092, 1093, 1094, 1095, 1089, 1090, 388, 29, 37, 42, 76, 77, 1096, 1091, 208, 284, 288, 289, 304, 305, 306, 307, 217, 335, 406, 408, 0, -220, 16, 17, 18, 383, 448, 455, 457, 462, 548, 620, 1039, 1042, 896, 1102, 1038, 1014, 559, 1013, 1079, 0, 0, -424, 1032, 0, 1043, 1045, 1044, 1047, 1046, 1061, 1176, 1161, 1157, 1174, 1076, 1208, 1103, 1156, 595); + protected $actionCheck = array(2, 3, 4, 5, 6, 7, 14, 9, 10, 11, 12, 13, 33, 34, 35, 36, 37, 38, 39, 40, 41, 0, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 9, 10, 11, 33, 34, 35, 36, 37, 38, 39, 40, 41, 8, 68, 69, 33, 34, 35, 36, 37, 56, 30, 8, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 70, 71, 72, 73, 74, 75, 76, 13, 1, 79, 115, 116, 117, 118, 119, 120, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 31, 132, 133, 134, 135, 136, 137, 138, 139, 140, 3, 4, 5, 6, 7, 146, 147, 148, 8, 12, 13, 158, 15, 33, 34, 35, 36, 37, 38, 39, 40, 41, 14, 43, 44, 45, 46, 13, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 33, 34, 35, 36, 49, 50, 13, 8, 8, 37, 55, 81, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 156, 69, 70, 71, 72, 58, 59, 37, 37, 77, 78, 79, 154, 81, 9, 10, 11, 85, 9, 10, 11, 79, 31, 1, 2, 154, 107, 9, 10, 11, 105, 112, 107, 126, 8, 30, 31, 105, 8, 30, 121, 32, 33, 34, 35, 36, 37, 115, 30, 155, 32, 33, 34, 35, 36, 123, 124, 115, 116, 117, 118, 119, 120, 115, 132, 133, 159, 135, 136, 137, 138, 139, 140, 141, 79, 156, 151, 82, 131, 147, 148, 133, 134, 151, 152, 153, 9, 10, 11, 157, 8, 159, 160, 158, 162, 73, 74, 75, 76, 150, 69, 79, 0, 1, 2, 83, 158, 30, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 8, 97, 150, 150, 81, 81, 102, 103, 104, 105, 13, 158, 108, 109, 9, 10, 11, 158, 114, 115, 116, 117, 9, 10, 11, 8, 122, 154, 8, 125, 126, 127, 128, 43, 44, 45, 46, 47, 48, 49, 50, 51, 79, 30, 131, 32, 33, 34, 35, 8, 1, 81, 9, 10, 11, 132, 81, 73, 154, 155, 156, 37, 154, 79, 1, 2, 115, 83, 155, 81, 86, 87, 88, 30, 90, 69, 92, 80, 94, 155, 157, 97, 159, 159, 133, 134, 102, 103, 104, 105, 8, 107, 108, 109, 9, 10, 112, 70, 114, 115, 116, 117, 9, 10, 11, 81, 122, 8, 81, 125, 126, 127, 128, 8, 151, 152, 153, 10, 11, 156, 161, 8, 158, 30, 84, 32, 33, 34, 79, 159, 146, 8, 157, 79, 159, 84, 73, 30, 154, 155, 156, 13, 79, 1, 2, 69, 83, 159, 156, 86, 87, 88, 69, 90, 13, 92, 132, 94, 69, 81, 97, 155, 99, 100, 101, 102, 103, 104, 105, 115, 9, 108, 109, 9, 10, 11, 79, 114, 115, 116, 117, 157, 142, 159, 157, 122, 159, 13, 125, 126, 127, 128, 8, 142, 30, 154, 32, 33, 52, 53, 54, 158, 56, 30, 155, 151, 152, 153, 159, 14, 52, 53, 54, 81, 68, 73, 84, 154, 155, 156, 131, 79, 33, 34, 35, 83, 68, 69, 86, 87, 88, 155, 90, 155, 92, 157, 94, 159, 155, 97, 158, 99, 100, 101, 102, 103, 104, 105, 13, 152, 108, 109, 11, 154, 1, 2, 114, 115, 116, 117, 9, 10, 11, 16, 122, 14, 31, 125, 126, 127, 128, 30, 9, 10, 11, 143, 144, 154, 9, 10, 11, 30, 154, 16, 31, 49, 50, 51, 49, 50, 51, 1, 2, 30, 16, 154, 154, 155, 156, 30, 13, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 37, 56, 73, 13, 1, 2, 33, 34, 79, 9, 10, 11, 83, 68, 154, 86, 87, 88, 155, 90, 16, 92, 159, 94, 155, 16, 97, 37, 159, 16, 30, 102, 103, 104, 31, 68, 69, 108, 109, 73, 16, 1, 2, 114, 115, 79, 105, 31, 107, 83, 31, 122, 86, 87, 88, 33, 90, 31, 92, 31, 94, 74, 75, 97, 31, 74, 75, 31, 102, 103, 104, 31, 100, 101, 108, 109, 73, 56, 1, 2, 114, 115, 79, 154, 155, 37, 83, 69, 122, 86, 87, 88, 69, 90, 69, 92, 69, 94, 110, 111, 97, 154, 155, 154, 155, 102, 103, 104, 31, 154, 155, 108, 109, 73, 68, 1, 2, 114, 115, 79, 154, 155, 69, 83, 69, 122, 86, 87, 88, 69, 90, 69, 92, 70, 94, 76, 79, 97, 84, 81, 84, 89, 102, 103, 104, 31, 81, 81, 108, 109, 73, 112, 88, 115, 114, 115, 79, 154, 155, 91, 83, 126, 122, 86, 87, 88, 93, 90, 96, 92, 95, 94, 96, 99, 97, 96, 96, 96, 129, 102, 103, 104, 99, 105, 113, 108, 109, 73, 145, 105, 129, 114, 115, 79, 154, 155, 126, 83, 131, 122, 86, 87, 88, 156, 90, 154, 92, 157, 94, -1, -1, 97, 130, -1, 145, -1, 102, 103, 104, 31, 131, 131, 108, 109, 131, -1, -1, 142, 114, 115, 142, 154, 155, -1, -1, 149, 122, 49, 50, 145, 145, 145, 145, 55, 145, 57, 145, 149, 156, 158, 150, -1, -1, 151, -1, -1, -1, 69, 154, 154, 154, 154, 154, 154, 154, 77, 78, 154, 154, 155, 49, 50, 154, 85, 154, 154, 55, 154, 57, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 69, 154, 154, 154, 154, 159, 155, 155, 77, 78, 155, 155, 155, 155, 155, 155, 85, 155, 155, 155, 155, 155, 155, 162, 156, 156, 156, 156, 156, 156, 156, 133, 156, 135, 136, 137, 138, 139, 140, 141, 156, 156, 156, 156, 156, 147, 148, 156, 156, 156, 156, 156, 156, 156, -1, 157, 156, 156, 156, 156, 156, 156, 156, -1, 133, 157, 135, 136, 137, 138, 139, 140, 141, 157, 157, 157, 157, 157, 147, 148, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, -1, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, -1, -1, 160, 160, -1, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161); + protected $actionBase = array(0, 226, 306, 385, 464, 285, 246, 246, 786, -2, -2, 146, -2, -2, -2, 649, 723, 760, 723, 575, 686, 612, 612, 612, 175, 153, 153, 153, 174, 890, 319, 62, 450, 463, 557, 609, 636, 496, 496, 496, 496, 136, 136, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 195, 75, 777, 517, 147, 778, 779, 780, 886, 727, 887, 832, 833, 682, 836, 837, 838, 839, 840, 831, 841, 907, 842, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 483, 573, 365, 209, 281, 407, 646, 646, 646, 646, 646, 646, 646, 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, 429, 834, 585, 585, 585, 563, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 495, 486, -21, -21, 415, 668, 335, 619, 222, 511, 213, 25, 25, 25, 25, 25, 148, 16, 4, 4, 4, 4, 151, 312, 312, 312, 312, 119, 119, 119, 119, 346, 346, 123, 245, 245, 349, 400, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 111, 558, 558, 561, 561, 310, 152, 152, 152, 152, 704, 273, 273, 129, 371, 371, 371, 373, 734, 797, 376, 376, 376, 376, 376, 376, 468, 468, 468, 480, 480, 480, 702, 587, 454, 587, 454, 684, 748, 509, 748, 700, 199, 515, 803, 398, 720, 829, 729, 830, 601, 747, 235, 782, 724, 419, 782, 633, 637, 634, 419, 419, 715, 98, 863, 292, 195, 595, 405, 667, 781, 421, 732, 784, 363, 445, 411, 593, 328, 286, 744, 785, 888, 889, 181, 739, 667, 667, 667, 139, 362, 328, -8, 613, 613, 613, 613, 48, 613, 613, 613, 613, 314, 230, 506, 404, 783, 703, 703, 712, 694, 852, 696, 696, 703, 711, 703, 712, 694, 854, 854, 854, 854, 703, 694, 703, 703, 703, 696, 696, 694, 709, 696, 38, 694, 695, 707, 707, 854, 751, 752, 703, 703, 728, 696, 696, 696, 728, 694, 854, 685, 746, 234, 696, 854, 665, 711, 665, 703, 685, 694, 665, 711, 711, 665, 21, 662, 664, 853, 855, 869, 792, 681, 716, 861, 862, 856, 860, 844, 679, 753, 754, 569, 669, 671, 673, 699, 740, 701, 735, 724, 692, 692, 692, 713, 741, 713, 692, 692, 692, 692, 692, 692, 692, 692, 893, 689, 745, 736, 710, 755, 589, 600, 793, 731, 738, 882, 875, 891, 892, 863, 880, 713, 894, 697, 180, 650, 864, 693, 788, 713, 865, 713, 794, 713, 883, 804, 708, 805, 806, 692, 884, 895, 896, 897, 898, 899, 900, 901, 902, 706, 903, 756, 698, 876, 339, 859, 715, 742, 725, 791, 759, 807, 342, 904, 808, 713, 713, 795, 787, 713, 796, 764, 750, 872, 766, 877, 905, 731, 726, 878, 713, 730, 809, 906, 342, 672, 705, 737, 721, 767, 870, 885, 868, 798, 655, 659, 810, 812, 820, 674, 769, 873, 874, 871, 771, 799, 670, 800, 719, 821, 801, 866, 772, 822, 823, 881, 718, 743, 717, 722, 714, 802, 824, 879, 773, 774, 775, 827, 776, 828, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136, 136, 136, 136, -2, -2, -2, -2, 0, 0, -2, 0, 0, 0, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 0, 0, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 591, -21, -21, -21, -21, 591, -21, -21, -21, -21, -21, -21, -21, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, -21, 376, 591, 591, 591, -21, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, -21, 591, 0, 0, 591, -21, 591, -21, 591, -21, 591, 591, 591, 591, 591, 591, -21, -21, -21, -21, -21, -21, 0, 468, 468, 468, 468, -21, -21, -21, -21, 376, 376, -37, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 376, 468, 468, 480, 480, 376, 376, 376, 376, 376, -37, 376, 376, 419, 711, 711, 711, 454, 454, 454, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 454, 419, 0, 419, 0, 376, 419, 711, 419, 454, 711, 711, 419, 696, 618, 618, 618, 618, 342, 328, 0, 711, 711, 0, 711, 0, 0, 0, 0, 0, 696, 0, 703, 0, 0, 0, 0, 692, 180, 0, 725, 427, 0, 0, 0, 0, 0, 0, 725, 427, 435, 435, 0, 706, 692, 692, 692, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 342); + protected $actionDefault = array(3, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 534, 534, 489, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 293, 293, 293, 32767, 32767, 32767, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 32767, 32767, 32767, 32767, 32767, 32767, 376, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 382, 539, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 357, 358, 360, 361, 292, 542, 523, 241, 383, 538, 291, 243, 321, 493, 32767, 32767, 32767, 323, 120, 252, 197, 492, 123, 290, 228, 375, 377, 322, 297, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 296, 449, 32767, 354, 353, 352, 451, 486, 486, 489, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 450, 319, 477, 476, 320, 447, 324, 448, 326, 452, 325, 342, 343, 340, 341, 344, 454, 453, 470, 471, 468, 469, 295, 345, 346, 347, 348, 472, 473, 474, 475, 32767, 32767, 276, 533, 533, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 333, 334, 461, 462, 32767, 232, 232, 232, 232, 277, 232, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 328, 329, 327, 456, 457, 455, 423, 32767, 32767, 32767, 425, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 494, 32767, 32767, 32767, 32767, 32767, 507, 412, 32767, 404, 32767, 32767, 216, 218, 165, 32767, 32767, 480, 32767, 32767, 32767, 32767, 32767, 512, 338, 32767, 32767, 114, 32767, 32767, 32767, 549, 32767, 507, 32767, 114, 32767, 32767, 32767, 32767, 351, 330, 331, 332, 32767, 32767, 511, 505, 464, 465, 466, 467, 32767, 458, 459, 460, 463, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 169, 420, 426, 426, 32767, 32767, 32767, 32767, 169, 32767, 32767, 32767, 32767, 32767, 169, 32767, 32767, 32767, 510, 509, 169, 32767, 405, 488, 169, 182, 180, 180, 32767, 202, 202, 32767, 32767, 184, 481, 500, 32767, 184, 169, 32767, 393, 171, 488, 32767, 32767, 234, 32767, 234, 32767, 393, 169, 234, 32767, 32767, 234, 32767, 406, 430, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 372, 373, 483, 496, 32767, 497, 32767, 404, 336, 337, 339, 316, 32767, 318, 362, 363, 364, 365, 366, 367, 368, 370, 32767, 410, 32767, 413, 32767, 32767, 32767, 251, 32767, 547, 32767, 32767, 300, 547, 32767, 32767, 32767, 541, 32767, 32767, 294, 32767, 32767, 32767, 32767, 247, 32767, 167, 32767, 531, 32767, 548, 32767, 505, 32767, 335, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 506, 32767, 32767, 32767, 32767, 223, 32767, 443, 32767, 114, 32767, 32767, 32767, 183, 32767, 32767, 298, 242, 32767, 32767, 540, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 112, 32767, 168, 32767, 32767, 32767, 185, 32767, 32767, 505, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 289, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 505, 32767, 32767, 227, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 406, 32767, 270, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 125, 125, 3, 125, 125, 254, 3, 254, 125, 254, 254, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 210, 213, 202, 202, 162, 125, 125, 262); + protected $goto = array(165, 139, 139, 139, 165, 143, 146, 140, 141, 142, 148, 186, 167, 162, 162, 162, 162, 143, 143, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 137, 158, 159, 160, 161, 183, 138, 184, 489, 490, 367, 491, 495, 496, 497, 498, 499, 500, 501, 502, 959, 163, 144, 145, 147, 170, 175, 185, 203, 251, 254, 256, 258, 260, 261, 262, 263, 264, 265, 273, 274, 275, 276, 299, 300, 324, 325, 326, 384, 385, 386, 538, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 149, 150, 151, 166, 152, 168, 153, 204, 169, 154, 155, 156, 205, 157, 135, 616, 556, 574, 578, 622, 624, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 1099, 515, 345, 571, 600, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 1099, 504, 1202, 1202, 1075, 1074, 504, 540, 541, 542, 543, 544, 545, 546, 547, 549, 582, 3, 4, 173, 1202, 844, 844, 844, 844, 839, 845, 176, 177, 178, 391, 392, 393, 394, 172, 201, 206, 250, 255, 257, 259, 266, 267, 268, 269, 270, 271, 277, 278, 279, 280, 301, 302, 327, 328, 329, 396, 397, 398, 399, 174, 179, 252, 253, 180, 181, 182, 493, 493, 750, 493, 493, 493, 493, 493, 493, 493, 493, 493, 493, 493, 493, 493, 493, 505, 929, 442, 444, 627, 505, 751, 779, 1100, 610, 927, 880, 880, 765, 1190, 1190, 1168, 555, 775, 764, 743, 1168, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, 390, 602, 746, 532, 532, 564, 528, 530, 530, 492, 494, 520, 536, 565, 568, 579, 586, 810, 606, 506, 346, 347, 609, 850, 506, 365, 537, 746, 533, 746, 563, 430, 430, 375, 430, 430, 430, 430, 430, 430, 430, 430, 430, 430, 430, 430, 430, 430, 1063, 581, 957, 596, 597, 1063, 887, 887, 887, 887, 1160, 887, 887, 1182, 1182, 1182, 376, 376, 376, 749, 1063, 1063, 1063, 1063, 1063, 1063, 334, 1056, 317, 374, 374, 374, 866, 848, 846, 848, 650, 461, 507, 875, 870, 376, 1194, 368, 374, 389, 374, 898, 374, 1080, 583, 348, 404, 374, 1216, 590, 601, 1017, 19, 15, 361, 1148, 1187, 525, 936, 904, 510, 526, 904, 651, 551, 381, 1201, 1201, 587, 1007, 550, 877, 607, 608, 873, 612, 613, 619, 621, 626, 628, 23, 884, 937, 1201, 336, 598, 1059, 1060, 1204, 378, 1056, 557, 539, 893, 768, 766, 379, 514, 902, 509, 524, 655, 1057, 1159, 1057, 776, 509, 1167, 524, 514, 514, 1058, 1167, 1049, 907, 508, 1054, 511, 433, 434, 510, 1184, 1184, 1184, 854, 445, 945, 569, 1145, 459, 362, 0, 0, 773, 1209, 0, 518, 0, 519, 0, 529, 0, 0, 0, 0, 0, 1166, 0, 0, 0, 771, 0, 0, 0, 449, 0, 0, 0, 0, 0, 0, 605, 0, 0, 0, 0, 13, 1055, 614); + protected $gotoCheck = array(42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 56, 66, 59, 59, 59, 8, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 124, 99, 69, 39, 39, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 66, 140, 140, 122, 122, 66, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 29, 29, 26, 140, 66, 66, 66, 66, 66, 66, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 115, 115, 14, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 7, 7, 7, 7, 115, 15, 28, 7, 7, 7, 74, 74, 22, 74, 74, 116, 56, 22, 22, 5, 116, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 50, 50, 10, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 49, 60, 120, 69, 69, 60, 32, 120, 60, 2, 10, 107, 10, 2, 56, 56, 10, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 64, 99, 64, 64, 56, 56, 56, 56, 56, 79, 56, 56, 8, 8, 8, 121, 121, 121, 13, 56, 56, 56, 56, 56, 56, 123, 79, 123, 12, 12, 12, 13, 13, 13, 13, 13, 56, 13, 13, 13, 121, 138, 45, 12, 121, 12, 81, 12, 33, 67, 67, 67, 12, 12, 125, 48, 33, 33, 33, 33, 129, 136, 8, 95, 12, 12, 31, 12, 31, 31, 47, 139, 139, 31, 100, 33, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 33, 76, 95, 139, 17, 33, 79, 79, 139, 11, 79, 11, 46, 78, 24, 23, 16, 46, 82, 8, 8, 71, 79, 79, 79, 25, 8, 117, 8, 46, 46, 79, 117, 111, 83, 8, 113, 8, 8, 8, 12, 117, 117, 117, 68, 62, 97, 63, 128, 106, 57, -1, -1, 8, 8, -1, 57, -1, 99, -1, 57, -1, -1, -1, -1, -1, 117, -1, -1, -1, 8, -1, -1, -1, 57, -1, -1, -1, -1, -1, -1, 12, -1, -1, -1, -1, 57, 12, 12); + protected $gotoBase = array(0, 0, -249, 0, 0, 300, 0, 287, 105, 0, 47, 164, 118, 421, 274, 295, 171, 184, 0, 0, 0, 0, -49, 168, 172, 104, 24, 0, 288, -431, 0, -159, 359, 44, 0, 0, 0, 0, 0, 125, 0, 0, -24, 0, 0, 407, 479, 186, 178, 355, 75, 0, 0, 0, 0, 0, 106, 119, 0, -192, -81, 0, 101, 93, -231, 0, -90, 135, 121, -276, 0, 148, 0, 0, 21, 0, 183, 0, 194, 71, 0, 423, 155, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 0, 122, 0, 120, 176, 0, 0, 0, 0, 0, 83, 358, 170, 0, 0, 113, 0, 111, 0, -7, 9, 220, 0, 0, 77, 108, -102, 100, -42, 251, 0, 0, 89, 256, 0, 0, 0, 0, 0, 0, 181, 0, 419, 160, -107, 0, 0); + protected $gotoDefault = array(-32768, 463, 659, 2, 660, 733, 741, 593, 477, 625, 577, 370, 1178, 785, 786, 787, 371, 358, 478, 369, 400, 395, 774, 767, 769, 777, 171, 401, 780, 1, 782, 513, 818, 1008, 355, 790, 356, 585, 792, 522, 794, 795, 136, 372, 373, 523, 479, 380, 572, 809, 272, 377, 811, 357, 812, 821, 360, 460, 454, 552, 604, 425, 441, 566, 560, 531, 1072, 561, 853, 344, 861, 656, 869, 872, 480, 553, 883, 446, 891, 1085, 387, 897, 903, 908, 283, 911, 407, 402, 580, 916, 917, 5, 921, 617, 618, 8, 308, 944, 594, 958, 411, 1027, 1029, 481, 482, 517, 453, 503, 521, 483, 1050, 435, 403, 1053, 484, 485, 426, 427, 1069, 350, 1153, 349, 443, 316, 1140, 575, 1104, 450, 1193, 1149, 343, 486, 487, 366, 1172, 382, 1188, 431, 1195, 1203, 339, 535, 562); + protected $ruleToNonTerminal = array(0, 1, 3, 3, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 8, 9, 10, 10, 11, 11, 12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 17, 17, 18, 18, 20, 20, 16, 16, 21, 21, 22, 22, 23, 23, 24, 24, 19, 19, 25, 27, 27, 28, 29, 29, 31, 30, 30, 30, 30, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 13, 13, 53, 53, 55, 54, 54, 47, 47, 57, 57, 58, 58, 14, 15, 15, 15, 61, 61, 61, 62, 62, 65, 65, 63, 63, 67, 67, 40, 40, 49, 49, 52, 52, 52, 51, 51, 68, 41, 41, 41, 41, 69, 69, 70, 70, 71, 71, 38, 38, 34, 34, 72, 36, 36, 73, 35, 35, 37, 37, 48, 48, 48, 59, 59, 75, 75, 76, 76, 78, 78, 78, 77, 77, 60, 60, 79, 79, 79, 80, 80, 81, 81, 81, 43, 43, 82, 82, 82, 44, 44, 83, 83, 84, 84, 64, 85, 85, 85, 85, 90, 90, 91, 91, 92, 92, 92, 92, 92, 93, 94, 94, 89, 89, 86, 86, 88, 88, 96, 96, 95, 95, 95, 95, 95, 95, 87, 87, 98, 97, 97, 45, 45, 39, 39, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 33, 33, 46, 46, 103, 103, 104, 104, 104, 104, 110, 99, 99, 106, 106, 112, 112, 113, 114, 114, 114, 114, 114, 114, 66, 66, 56, 56, 56, 56, 100, 100, 118, 118, 115, 115, 119, 119, 119, 119, 101, 101, 101, 105, 105, 105, 111, 111, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 26, 26, 26, 26, 26, 26, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 109, 109, 102, 102, 102, 102, 125, 125, 128, 128, 127, 127, 129, 129, 50, 50, 50, 50, 131, 131, 130, 130, 130, 130, 130, 132, 132, 117, 117, 120, 120, 116, 116, 134, 133, 133, 133, 133, 121, 121, 121, 121, 108, 108, 122, 122, 122, 122, 74, 135, 135, 136, 136, 136, 107, 107, 137, 137, 138, 138, 138, 138, 138, 123, 123, 123, 123, 140, 141, 139, 139, 139, 139, 139, 139, 139, 142, 142, 142); + protected $ruleToLength = array(1, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 4, 3, 4, 2, 3, 1, 1, 7, 6, 3, 1, 3, 1, 3, 1, 1, 3, 1, 3, 1, 2, 3, 1, 3, 3, 1, 3, 2, 0, 1, 1, 1, 1, 1, 3, 5, 8, 3, 5, 9, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 1, 2, 2, 5, 7, 9, 5, 6, 3, 3, 2, 2, 1, 1, 1, 0, 2, 8, 0, 4, 1, 3, 0, 1, 0, 1, 10, 7, 6, 5, 1, 2, 2, 0, 2, 0, 2, 0, 2, 1, 3, 1, 4, 1, 4, 1, 1, 4, 1, 3, 3, 3, 4, 4, 5, 0, 2, 4, 3, 1, 1, 1, 4, 0, 2, 3, 0, 2, 4, 0, 2, 0, 3, 1, 2, 1, 1, 0, 1, 3, 4, 6, 1, 1, 1, 0, 1, 0, 2, 2, 3, 3, 1, 3, 1, 2, 2, 3, 1, 1, 2, 4, 3, 1, 1, 3, 2, 0, 1, 3, 3, 9, 3, 1, 3, 0, 2, 4, 5, 4, 4, 4, 3, 1, 1, 1, 3, 1, 1, 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 3, 1, 0, 1, 1, 3, 3, 4, 4, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 5, 4, 3, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 2, 1, 2, 10, 11, 3, 3, 2, 4, 4, 3, 4, 4, 4, 4, 7, 3, 2, 0, 4, 1, 3, 2, 2, 4, 6, 2, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 4, 4, 0, 2, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 3, 1, 4, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 4, 3, 1, 3, 1, 1, 3, 3, 0, 2, 0, 1, 3, 1, 3, 1, 1, 1, 1, 1, 6, 4, 3, 4, 2, 4, 4, 1, 3, 1, 2, 1, 1, 4, 1, 1, 3, 6, 4, 4, 4, 4, 1, 4, 0, 1, 1, 3, 1, 1, 4, 3, 1, 1, 1, 0, 0, 2, 3, 1, 3, 1, 4, 2, 2, 2, 2, 1, 2, 1, 1, 1, 4, 3, 3, 3, 6, 3, 1, 1, 1); + protected function initReduceCallbacks() + { + $this->reduceCallbacks = [0 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 1 => function ($stackPos) { + $this->semValue = $this->handleNamespaces($this->semStack[$stackPos - (1 - 1)]); + }, 2 => function ($stackPos) { + if (\is_array($this->semStack[$stackPos - (2 - 2)])) { + $this->semValue = \array_merge($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); + } else { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } + }, 3 => function ($stackPos) { + $this->semValue = array(); + }, 4 => function ($stackPos) { + $startAttributes = $this->lookaheadStartAttributes; + if (isset($startAttributes['comments'])) { + $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); + } else { + $nop = null; + } + if ($nop !== null) { + $this->semStack[$stackPos - (1 - 1)][] = $nop; + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 5 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 6 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 7 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 8 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 9 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 10 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 11 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 12 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 13 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 14 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 15 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 16 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 17 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 18 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 19 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 20 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 21 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 22 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 23 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 24 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 25 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 26 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 27 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 28 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 29 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 30 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 31 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 32 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 33 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 34 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 35 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 36 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 37 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 38 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 39 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 40 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 41 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 42 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 43 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 44 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 45 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 46 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 47 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 48 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 49 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 50 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 51 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 52 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 53 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 54 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 55 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 56 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 57 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 58 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 59 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 60 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 61 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 62 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 63 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 64 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 65 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 66 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 67 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 68 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 69 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 70 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 71 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 72 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 73 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 74 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 75 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 76 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 77 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 78 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 79 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 80 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 81 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 82 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 83 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 84 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 85 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 86 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 87 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 88 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 89 => function ($stackPos) { + $this->semValue = new Name(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 90 => function ($stackPos) { + $this->semValue = new Expr\Variable(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 91 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 92 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 93 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 94 => function ($stackPos) { + $this->semValue = new Stmt\HaltCompiler($this->lexer->handleHaltCompiler(), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 95 => function ($stackPos) { + $this->semValue = new Stmt\Namespace_($this->semStack[$stackPos - (3 - 2)], null, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON); + $this->checkNamespace($this->semValue); + }, 96 => function ($stackPos) { + $this->semValue = new Stmt\Namespace_($this->semStack[$stackPos - (5 - 2)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $this->checkNamespace($this->semValue); + }, 97 => function ($stackPos) { + $this->semValue = new Stmt\Namespace_(null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $this->checkNamespace($this->semValue); + }, 98 => function ($stackPos) { + $this->semValue = new Stmt\Use_($this->semStack[$stackPos - (3 - 2)], Stmt\Use_::TYPE_NORMAL, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 99 => function ($stackPos) { + $this->semValue = new Stmt\Use_($this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 100 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 101 => function ($stackPos) { + $this->semValue = new Stmt\Const_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 102 => function ($stackPos) { + $this->semValue = Stmt\Use_::TYPE_FUNCTION; + }, 103 => function ($stackPos) { + $this->semValue = Stmt\Use_::TYPE_CONSTANT; + }, 104 => function ($stackPos) { + $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 6)], $this->semStack[$stackPos - (7 - 2)], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 105 => function ($stackPos) { + $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 5)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 106 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 107 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 108 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 109 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 110 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 111 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 112 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (1 - 1)); + }, 113 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (3 - 3)); + }, 114 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (1 - 1)); + }, 115 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (3 - 3)); + }, 116 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + $this->semValue->type = Stmt\Use_::TYPE_NORMAL; + }, 117 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue->type = $this->semStack[$stackPos - (2 - 1)]; + }, 118 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 119 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 120 => function ($stackPos) { + $this->semValue = new Node\Const_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 121 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 122 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 123 => function ($stackPos) { + $this->semValue = new Node\Const_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 124 => function ($stackPos) { + if (\is_array($this->semStack[$stackPos - (2 - 2)])) { + $this->semValue = \array_merge($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); + } else { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } + }, 125 => function ($stackPos) { + $this->semValue = array(); + }, 126 => function ($stackPos) { + $startAttributes = $this->lookaheadStartAttributes; + if (isset($startAttributes['comments'])) { + $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); + } else { + $nop = null; + } + if ($nop !== null) { + $this->semStack[$stackPos - (1 - 1)][] = $nop; + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 127 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 128 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 129 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 130 => function ($stackPos) { + throw new Error('__HALT_COMPILER() can only be used from the outermost scope', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 131 => function ($stackPos) { + if ($this->semStack[$stackPos - (3 - 2)]) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + $attrs = $this->startAttributeStack[$stackPos - (3 - 1)]; + $stmts = $this->semValue; + if (!empty($attrs['comments'])) { + $stmts[0]->setAttribute('comments', \array_merge($attrs['comments'], $stmts[0]->getAttribute('comments', []))); + } + } else { + $startAttributes = $this->startAttributeStack[$stackPos - (3 - 1)]; + if (isset($startAttributes['comments'])) { + $this->semValue = new Stmt\Nop($startAttributes + $this->endAttributes); + } else { + $this->semValue = null; + } + if (null === $this->semValue) { + $this->semValue = array(); + } + } + }, 132 => function ($stackPos) { + $this->semValue = new Stmt\If_($this->semStack[$stackPos - (5 - 2)], ['stmts' => \is_array($this->semStack[$stackPos - (5 - 3)]) ? $this->semStack[$stackPos - (5 - 3)] : array($this->semStack[$stackPos - (5 - 3)]), 'elseifs' => $this->semStack[$stackPos - (5 - 4)], 'else' => $this->semStack[$stackPos - (5 - 5)]], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 133 => function ($stackPos) { + $this->semValue = new Stmt\If_($this->semStack[$stackPos - (8 - 2)], ['stmts' => $this->semStack[$stackPos - (8 - 4)], 'elseifs' => $this->semStack[$stackPos - (8 - 5)], 'else' => $this->semStack[$stackPos - (8 - 6)]], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + }, 134 => function ($stackPos) { + $this->semValue = new Stmt\While_($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 135 => function ($stackPos) { + $this->semValue = new Stmt\Do_($this->semStack[$stackPos - (5 - 4)], \is_array($this->semStack[$stackPos - (5 - 2)]) ? $this->semStack[$stackPos - (5 - 2)] : array($this->semStack[$stackPos - (5 - 2)]), $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 136 => function ($stackPos) { + $this->semValue = new Stmt\For_(['init' => $this->semStack[$stackPos - (9 - 3)], 'cond' => $this->semStack[$stackPos - (9 - 5)], 'loop' => $this->semStack[$stackPos - (9 - 7)], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 137 => function ($stackPos) { + $this->semValue = new Stmt\Switch_($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 138 => function ($stackPos) { + $this->semValue = new Stmt\Break_(null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 139 => function ($stackPos) { + $this->semValue = new Stmt\Break_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 140 => function ($stackPos) { + $this->semValue = new Stmt\Continue_(null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 141 => function ($stackPos) { + $this->semValue = new Stmt\Continue_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 142 => function ($stackPos) { + $this->semValue = new Stmt\Return_(null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 143 => function ($stackPos) { + $this->semValue = new Stmt\Return_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 144 => function ($stackPos) { + $this->semValue = new Stmt\Global_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 145 => function ($stackPos) { + $this->semValue = new Stmt\Static_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 146 => function ($stackPos) { + $this->semValue = new Stmt\Echo_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 147 => function ($stackPos) { + $this->semValue = new Stmt\InlineHTML($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 148 => function ($stackPos) { + $this->semValue = new Stmt\Expression($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 149 => function ($stackPos) { + $this->semValue = new Stmt\Expression($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 150 => function ($stackPos) { + $this->semValue = new Stmt\Unset_($this->semStack[$stackPos - (5 - 3)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 151 => function ($stackPos) { + $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 5)][0], ['keyVar' => null, 'byRef' => $this->semStack[$stackPos - (7 - 5)][1], 'stmts' => $this->semStack[$stackPos - (7 - 7)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 152 => function ($stackPos) { + $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (9 - 3)], $this->semStack[$stackPos - (9 - 7)][0], ['keyVar' => $this->semStack[$stackPos - (9 - 5)], 'byRef' => $this->semStack[$stackPos - (9 - 7)][1], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 153 => function ($stackPos) { + $this->semValue = new Stmt\Declare_($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 154 => function ($stackPos) { + $this->semValue = new Stmt\TryCatch($this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 5)], $this->semStack[$stackPos - (6 - 6)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + $this->checkTryCatch($this->semValue); + }, 155 => function ($stackPos) { + $this->semValue = new Stmt\Throw_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 156 => function ($stackPos) { + $this->semValue = new Stmt\Goto_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 157 => function ($stackPos) { + $this->semValue = new Stmt\Label($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 158 => function ($stackPos) { + $this->semValue = new Stmt\Expression($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 159 => function ($stackPos) { + $this->semValue = array(); + /* means: no statement */ + }, 160 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 161 => function ($stackPos) { + $startAttributes = $this->startAttributeStack[$stackPos - (1 - 1)]; + if (isset($startAttributes['comments'])) { + $this->semValue = new Stmt\Nop($startAttributes + $this->endAttributes); + } else { + $this->semValue = null; + } + if ($this->semValue === null) { + $this->semValue = array(); + } + /* means: no statement */ + }, 162 => function ($stackPos) { + $this->semValue = array(); + }, 163 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 164 => function ($stackPos) { + $this->semValue = new Stmt\Catch_(array($this->semStack[$stackPos - (8 - 3)]), $this->semStack[$stackPos - (8 - 4)], $this->semStack[$stackPos - (8 - 7)], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + }, 165 => function ($stackPos) { + $this->semValue = null; + }, 166 => function ($stackPos) { + $this->semValue = new Stmt\Finally_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 167 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 168 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 169 => function ($stackPos) { + $this->semValue = \false; + }, 170 => function ($stackPos) { + $this->semValue = \true; + }, 171 => function ($stackPos) { + $this->semValue = \false; + }, 172 => function ($stackPos) { + $this->semValue = \true; + }, 173 => function ($stackPos) { + $this->semValue = new Stmt\Function_($this->semStack[$stackPos - (10 - 3)], ['byRef' => $this->semStack[$stackPos - (10 - 2)], 'params' => $this->semStack[$stackPos - (10 - 5)], 'returnType' => $this->semStack[$stackPos - (10 - 7)], 'stmts' => $this->semStack[$stackPos - (10 - 9)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); + }, 174 => function ($stackPos) { + $this->semValue = new Stmt\Class_($this->semStack[$stackPos - (7 - 2)], ['type' => $this->semStack[$stackPos - (7 - 1)], 'extends' => $this->semStack[$stackPos - (7 - 3)], 'implements' => $this->semStack[$stackPos - (7 - 4)], 'stmts' => $this->semStack[$stackPos - (7 - 6)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + $this->checkClass($this->semValue, $stackPos - (7 - 2)); + }, 175 => function ($stackPos) { + $this->semValue = new Stmt\Interface_($this->semStack[$stackPos - (6 - 2)], ['extends' => $this->semStack[$stackPos - (6 - 3)], 'stmts' => $this->semStack[$stackPos - (6 - 5)]], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + $this->checkInterface($this->semValue, $stackPos - (6 - 2)); + }, 176 => function ($stackPos) { + $this->semValue = new Stmt\Trait_($this->semStack[$stackPos - (5 - 2)], ['stmts' => $this->semStack[$stackPos - (5 - 4)]], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 177 => function ($stackPos) { + $this->semValue = 0; + }, 178 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_ABSTRACT; + }, 179 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_FINAL; + }, 180 => function ($stackPos) { + $this->semValue = null; + }, 181 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 182 => function ($stackPos) { + $this->semValue = array(); + }, 183 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 184 => function ($stackPos) { + $this->semValue = array(); + }, 185 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 186 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 187 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 188 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 189 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 190 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 191 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 192 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 193 => function ($stackPos) { + $this->semValue = null; + }, 194 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 195 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 196 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 197 => function ($stackPos) { + $this->semValue = new Stmt\DeclareDeclare($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 198 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 199 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 3)]; + }, 200 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 201 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (5 - 3)]; + }, 202 => function ($stackPos) { + $this->semValue = array(); + }, 203 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 204 => function ($stackPos) { + $this->semValue = new Stmt\Case_($this->semStack[$stackPos - (4 - 2)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 205 => function ($stackPos) { + $this->semValue = new Stmt\Case_(null, $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 206 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 207 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 208 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 209 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 210 => function ($stackPos) { + $this->semValue = array(); + }, 211 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 212 => function ($stackPos) { + $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos - (3 - 2)], \is_array($this->semStack[$stackPos - (3 - 3)]) ? $this->semStack[$stackPos - (3 - 3)] : array($this->semStack[$stackPos - (3 - 3)]), $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 213 => function ($stackPos) { + $this->semValue = array(); + }, 214 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 215 => function ($stackPos) { + $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos - (4 - 2)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 216 => function ($stackPos) { + $this->semValue = null; + }, 217 => function ($stackPos) { + $this->semValue = new Stmt\Else_(\is_array($this->semStack[$stackPos - (2 - 2)]) ? $this->semStack[$stackPos - (2 - 2)] : array($this->semStack[$stackPos - (2 - 2)]), $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 218 => function ($stackPos) { + $this->semValue = null; + }, 219 => function ($stackPos) { + $this->semValue = new Stmt\Else_($this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 220 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); + }, 221 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (2 - 2)], \true); + }, 222 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); + }, 223 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 224 => function ($stackPos) { + $this->semValue = array(); + }, 225 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 226 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 227 => function ($stackPos) { + $this->semValue = new Node\Param($this->semStack[$stackPos - (4 - 4)], null, $this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 2)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + $this->checkParam($this->semValue); + }, 228 => function ($stackPos) { + $this->semValue = new Node\Param($this->semStack[$stackPos - (6 - 4)], $this->semStack[$stackPos - (6 - 6)], $this->semStack[$stackPos - (6 - 1)], $this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 3)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + $this->checkParam($this->semValue); + }, 229 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 230 => function ($stackPos) { + $this->semValue = new Node\Identifier('array', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 231 => function ($stackPos) { + $this->semValue = new Node\Identifier('callable', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 232 => function ($stackPos) { + $this->semValue = null; + }, 233 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 234 => function ($stackPos) { + $this->semValue = null; + }, 235 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 236 => function ($stackPos) { + $this->semValue = array(); + }, 237 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 238 => function ($stackPos) { + $this->semValue = array(new Node\Arg($this->semStack[$stackPos - (3 - 2)], \false, \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes)); + }, 239 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 240 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 241 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (1 - 1)], \false, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 242 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (2 - 2)], \true, \false, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 243 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (2 - 2)], \false, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 244 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 245 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 246 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 247 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 248 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 249 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 250 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 251 => function ($stackPos) { + $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos - (1 - 1)], null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 252 => function ($stackPos) { + $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 253 => function ($stackPos) { + if ($this->semStack[$stackPos - (2 - 2)] !== null) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } + }, 254 => function ($stackPos) { + $this->semValue = array(); + }, 255 => function ($stackPos) { + $startAttributes = $this->lookaheadStartAttributes; + if (isset($startAttributes['comments'])) { + $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); + } else { + $nop = null; + } + if ($nop !== null) { + $this->semStack[$stackPos - (1 - 1)][] = $nop; + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 256 => function ($stackPos) { + $this->semValue = new Stmt\Property($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->checkProperty($this->semValue, $stackPos - (3 - 1)); + }, 257 => function ($stackPos) { + $this->semValue = new Stmt\ClassConst($this->semStack[$stackPos - (3 - 2)], 0, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 258 => function ($stackPos) { + $this->semValue = new Stmt\ClassMethod($this->semStack[$stackPos - (9 - 4)], ['type' => $this->semStack[$stackPos - (9 - 1)], 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 6)], 'returnType' => $this->semStack[$stackPos - (9 - 8)], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + $this->checkClassMethod($this->semValue, $stackPos - (9 - 1)); + }, 259 => function ($stackPos) { + $this->semValue = new Stmt\TraitUse($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 260 => function ($stackPos) { + $this->semValue = array(); + }, 261 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 262 => function ($stackPos) { + $this->semValue = array(); + }, 263 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 264 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Precedence($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 265 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (5 - 1)][0], $this->semStack[$stackPos - (5 - 1)][1], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 266 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], $this->semStack[$stackPos - (4 - 3)], null, $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 267 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 268 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 269 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); + }, 270 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 271 => function ($stackPos) { + $this->semValue = array(null, $this->semStack[$stackPos - (1 - 1)]); + }, 272 => function ($stackPos) { + $this->semValue = null; + }, 273 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 274 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 275 => function ($stackPos) { + $this->semValue = 0; + }, 276 => function ($stackPos) { + $this->semValue = 0; + }, 277 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 278 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 279 => function ($stackPos) { + $this->checkModifier($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $this->semValue = $this->semStack[$stackPos - (2 - 1)] | $this->semStack[$stackPos - (2 - 2)]; + }, 280 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PUBLIC; + }, 281 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PROTECTED; + }, 282 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PRIVATE; + }, 283 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_STATIC; + }, 284 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_ABSTRACT; + }, 285 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_FINAL; + }, 286 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 287 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 288 => function ($stackPos) { + $this->semValue = new Node\VarLikeIdentifier(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 289 => function ($stackPos) { + $this->semValue = new Stmt\PropertyProperty($this->semStack[$stackPos - (1 - 1)], null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 290 => function ($stackPos) { + $this->semValue = new Stmt\PropertyProperty($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 291 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 292 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 293 => function ($stackPos) { + $this->semValue = array(); + }, 294 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 295 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 296 => function ($stackPos) { + $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 297 => function ($stackPos) { + $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 298 => function ($stackPos) { + $this->semValue = new Expr\AssignRef($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 299 => function ($stackPos) { + $this->semValue = new Expr\AssignRef($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 300 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 301 => function ($stackPos) { + $this->semValue = new Expr\Clone_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 302 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 303 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 304 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 305 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 306 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 307 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 308 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 309 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 310 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 311 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 312 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 313 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 314 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Coalesce($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 315 => function ($stackPos) { + $this->semValue = new Expr\PostInc($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 316 => function ($stackPos) { + $this->semValue = new Expr\PreInc($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 317 => function ($stackPos) { + $this->semValue = new Expr\PostDec($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 318 => function ($stackPos) { + $this->semValue = new Expr\PreDec($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 319 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BooleanOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 320 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BooleanAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 321 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 322 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 323 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 324 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 325 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 326 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 327 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 328 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 329 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 330 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 331 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 332 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 333 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 334 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 335 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 336 => function ($stackPos) { + $this->semValue = new Expr\UnaryPlus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 337 => function ($stackPos) { + $this->semValue = new Expr\UnaryMinus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 338 => function ($stackPos) { + $this->semValue = new Expr\BooleanNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 339 => function ($stackPos) { + $this->semValue = new Expr\BitwiseNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 340 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Identical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 341 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\NotIdentical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 342 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Equal($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 343 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\NotEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 344 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Spaceship($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 345 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Smaller($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 346 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\SmallerOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 347 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Greater($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 348 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\GreaterOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 349 => function ($stackPos) { + $this->semValue = new Expr\Instanceof_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 350 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 351 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 352 => function ($stackPos) { + $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (5 - 1)], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 353 => function ($stackPos) { + $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (4 - 1)], null, $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 354 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Coalesce($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 355 => function ($stackPos) { + $this->semValue = new Expr\Isset_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 356 => function ($stackPos) { + $this->semValue = new Expr\Empty_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 357 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 358 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE_ONCE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 359 => function ($stackPos) { + $this->semValue = new Expr\Eval_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 360 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 361 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE_ONCE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 362 => function ($stackPos) { + $this->semValue = new Expr\Cast\Int_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 363 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes; + $attrs['kind'] = $this->getFloatCastKind($this->semStack[$stackPos - (2 - 1)]); + $this->semValue = new Expr\Cast\Double($this->semStack[$stackPos - (2 - 2)], $attrs); + }, 364 => function ($stackPos) { + $this->semValue = new Expr\Cast\String_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 365 => function ($stackPos) { + $this->semValue = new Expr\Cast\Array_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 366 => function ($stackPos) { + $this->semValue = new Expr\Cast\Object_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 367 => function ($stackPos) { + $this->semValue = new Expr\Cast\Bool_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 368 => function ($stackPos) { + $this->semValue = new Expr\Cast\Unset_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 369 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes; + $attrs['kind'] = \strtolower($this->semStack[$stackPos - (2 - 1)]) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE; + $this->semValue = new Expr\Exit_($this->semStack[$stackPos - (2 - 2)], $attrs); + }, 370 => function ($stackPos) { + $this->semValue = new Expr\ErrorSuppress($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 371 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 372 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 373 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 374 => function ($stackPos) { + $this->semValue = new Expr\ShellExec($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 375 => function ($stackPos) { + $this->semValue = new Expr\Print_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 376 => function ($stackPos) { + $this->semValue = new Expr\Yield_(null, null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 377 => function ($stackPos) { + $this->semValue = new Expr\YieldFrom($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 378 => function ($stackPos) { + $this->semValue = new Expr\Closure(['static' => \false, 'byRef' => $this->semStack[$stackPos - (10 - 2)], 'params' => $this->semStack[$stackPos - (10 - 4)], 'uses' => $this->semStack[$stackPos - (10 - 6)], 'returnType' => $this->semStack[$stackPos - (10 - 7)], 'stmts' => $this->semStack[$stackPos - (10 - 9)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); + }, 379 => function ($stackPos) { + $this->semValue = new Expr\Closure(['static' => \true, 'byRef' => $this->semStack[$stackPos - (11 - 3)], 'params' => $this->semStack[$stackPos - (11 - 5)], 'uses' => $this->semStack[$stackPos - (11 - 7)], 'returnType' => $this->semStack[$stackPos - (11 - 8)], 'stmts' => $this->semStack[$stackPos - (11 - 10)]], $this->startAttributeStack[$stackPos - (11 - 1)] + $this->endAttributes); + }, 380 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 381 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 382 => function ($stackPos) { + $this->semValue = new Expr\Yield_($this->semStack[$stackPos - (2 - 2)], null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 383 => function ($stackPos) { + $this->semValue = new Expr\Yield_($this->semStack[$stackPos - (4 - 4)], $this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 384 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes; + $attrs['kind'] = Expr\Array_::KIND_LONG; + $this->semValue = new Expr\Array_($this->semStack[$stackPos - (4 - 3)], $attrs); + }, 385 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes; + $attrs['kind'] = Expr\Array_::KIND_SHORT; + $this->semValue = new Expr\Array_($this->semStack[$stackPos - (3 - 2)], $attrs); + }, 386 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 387 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes; + $attrs['kind'] = $this->semStack[$stackPos - (4 - 1)][0] === "'" || $this->semStack[$stackPos - (4 - 1)][1] === "'" && ($this->semStack[$stackPos - (4 - 1)][0] === 'b' || $this->semStack[$stackPos - (4 - 1)][0] === 'B') ? Scalar\String_::KIND_SINGLE_QUOTED : Scalar\String_::KIND_DOUBLE_QUOTED; + $this->semValue = new Expr\ArrayDimFetch(new Scalar\String_(Scalar\String_::parse($this->semStack[$stackPos - (4 - 1)]), $attrs), $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 388 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 389 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 390 => function ($stackPos) { + $this->semValue = array(new Stmt\Class_(null, ['type' => 0, 'extends' => $this->semStack[$stackPos - (7 - 3)], 'implements' => $this->semStack[$stackPos - (7 - 4)], 'stmts' => $this->semStack[$stackPos - (7 - 6)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes), $this->semStack[$stackPos - (7 - 2)]); + $this->checkClass($this->semValue[0], -1); + }, 391 => function ($stackPos) { + $this->semValue = new Expr\New_($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 392 => function ($stackPos) { + list($class, $ctorArgs) = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = new Expr\New_($class, $ctorArgs, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 393 => function ($stackPos) { + $this->semValue = array(); + }, 394 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 3)]; + }, 395 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 396 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 397 => function ($stackPos) { + $this->semValue = new Expr\ClosureUse($this->semStack[$stackPos - (2 - 2)], $this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 398 => function ($stackPos) { + $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 399 => function ($stackPos) { + $this->semValue = new Expr\StaticCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 400 => function ($stackPos) { + $this->semValue = new Expr\StaticCall($this->semStack[$stackPos - (6 - 1)], $this->semStack[$stackPos - (6 - 4)], $this->semStack[$stackPos - (6 - 6)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 401 => function ($stackPos) { + $this->semValue = $this->fixupPhp5StaticPropCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 402 => function ($stackPos) { + $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 403 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 404 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 405 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 406 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 407 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 408 => function ($stackPos) { + $this->semValue = new Name\FullyQualified(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 409 => function ($stackPos) { + $this->semValue = new Name\Relative(\substr($this->semStack[$stackPos - (1 - 1)], 10), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 410 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 411 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 412 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 413 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 414 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 415 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 416 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 417 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 418 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 419 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 420 => function ($stackPos) { + $this->semValue = null; + }, 421 => function ($stackPos) { + $this->semValue = null; + }, 422 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 423 => function ($stackPos) { + $this->semValue = array(); + }, 424 => function ($stackPos) { + $this->semValue = array(new Scalar\EncapsedStringPart(Scalar\String_::parseEscapeSequences($this->semStack[$stackPos - (1 - 1)], '`', \false), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes)); + }, 425 => function ($stackPos) { + foreach ($this->semStack[$stackPos - (1 - 1)] as $s) { + if ($s instanceof Node\Scalar\EncapsedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', \false); + } + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 426 => function ($stackPos) { + $this->semValue = array(); + }, 427 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 428 => function ($stackPos) { + $this->semValue = $this->parseLNumber($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes, \true); + }, 429 => function ($stackPos) { + $this->semValue = new Scalar\DNumber(Scalar\DNumber::parse($this->semStack[$stackPos - (1 - 1)]), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 430 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes; + $attrs['kind'] = $this->semStack[$stackPos - (1 - 1)][0] === "'" || $this->semStack[$stackPos - (1 - 1)][1] === "'" && ($this->semStack[$stackPos - (1 - 1)][0] === 'b' || $this->semStack[$stackPos - (1 - 1)][0] === 'B') ? Scalar\String_::KIND_SINGLE_QUOTED : Scalar\String_::KIND_DOUBLE_QUOTED; + $this->semValue = new Scalar\String_(Scalar\String_::parse($this->semStack[$stackPos - (1 - 1)], \false), $attrs); + }, 431 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Line($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 432 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\File($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 433 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Dir($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 434 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Class_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 435 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Trait_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 436 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Method($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 437 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Function_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 438 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Namespace_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 439 => function ($stackPos) { + $this->semValue = $this->parseDocString($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)], \false); + }, 440 => function ($stackPos) { + $this->semValue = $this->parseDocString($this->semStack[$stackPos - (2 - 1)], '', $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (2 - 2)] + $this->endAttributeStack[$stackPos - (2 - 2)], \false); + }, 441 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 442 => function ($stackPos) { + $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 443 => function ($stackPos) { + $this->semValue = new Expr\ConstFetch($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 444 => function ($stackPos) { + $this->semValue = new Expr\Array_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 445 => function ($stackPos) { + $this->semValue = new Expr\Array_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 446 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 447 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BooleanOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 448 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BooleanAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 449 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 450 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 451 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 452 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 453 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 454 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 455 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 456 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 457 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 458 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 459 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 460 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 461 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 462 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 463 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 464 => function ($stackPos) { + $this->semValue = new Expr\UnaryPlus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 465 => function ($stackPos) { + $this->semValue = new Expr\UnaryMinus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 466 => function ($stackPos) { + $this->semValue = new Expr\BooleanNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 467 => function ($stackPos) { + $this->semValue = new Expr\BitwiseNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 468 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Identical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 469 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\NotIdentical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 470 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Equal($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 471 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\NotEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 472 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Smaller($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 473 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\SmallerOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 474 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Greater($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 475 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\GreaterOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 476 => function ($stackPos) { + $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (5 - 1)], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 477 => function ($stackPos) { + $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (4 - 1)], null, $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 478 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 479 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 480 => function ($stackPos) { + $this->semValue = new Expr\ConstFetch($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 481 => function ($stackPos) { + $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 482 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 483 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 484 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes; + $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED; + foreach ($this->semStack[$stackPos - (3 - 2)] as $s) { + if ($s instanceof Node\Scalar\EncapsedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '"', \true); + } + } + $this->semValue = new Scalar\Encapsed($this->semStack[$stackPos - (3 - 2)], $attrs); + }, 485 => function ($stackPos) { + $this->semValue = $this->parseDocString($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)], \true); + }, 486 => function ($stackPos) { + $this->semValue = array(); + }, 487 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 488 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 489 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 490 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 491 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 492 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (3 - 3)], $this->semStack[$stackPos - (3 - 1)], \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 493 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 494 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 495 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 496 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 497 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 498 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 5)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 499 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 500 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 501 => function ($stackPos) { + $this->semValue = new Expr\MethodCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 502 => function ($stackPos) { + $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 503 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 504 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 505 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 506 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 507 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 508 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 509 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 510 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 511 => function ($stackPos) { + $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 512 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 513 => function ($stackPos) { + $var = \substr($this->semStack[$stackPos - (1 - 1)], 1); + $this->semValue = \is_string($var) ? new Node\VarLikeIdentifier($var, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes) : $var; + }, 514 => function ($stackPos) { + $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 515 => function ($stackPos) { + $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (6 - 1)], $this->semStack[$stackPos - (6 - 5)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 516 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 517 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 518 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 519 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 520 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 521 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 522 => function ($stackPos) { + $this->semValue = null; + }, 523 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 524 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 525 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 526 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 527 => function ($stackPos) { + $this->semValue = new Expr\Error($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->errorState = 2; + }, 528 => function ($stackPos) { + $this->semValue = new Expr\List_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 529 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 530 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 531 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 532 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 533 => function ($stackPos) { + $this->semValue = null; + }, 534 => function ($stackPos) { + $this->semValue = array(); + }, 535 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 536 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 537 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 538 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (3 - 3)], $this->semStack[$stackPos - (3 - 1)], \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 539 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 540 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (4 - 4)], $this->semStack[$stackPos - (4 - 1)], \true, $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 541 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (2 - 2)], null, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 542 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (2 - 2)], null, \false, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 543 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 544 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 545 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 546 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); + }, 547 => function ($stackPos) { + $this->semValue = new Scalar\EncapsedStringPart($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 548 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 549 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 550 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 551 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 552 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 553 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 554 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 4)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 555 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 556 => function ($stackPos) { + $this->semValue = new Scalar\String_($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 557 => function ($stackPos) { + $this->semValue = $this->parseNumString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 558 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }]; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Parser/Php7.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Parser/Php7.php new file mode 100644 index 000000000..08fd65e87 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Parser/Php7.php @@ -0,0 +1,1348 @@ +'", "T_IS_GREATER_OR_EQUAL", "T_SL", "T_SR", "'+'", "'-'", "'.'", "'*'", "'/'", "'%'", "'!'", "T_INSTANCEOF", "'~'", "T_INC", "T_DEC", "T_INT_CAST", "T_DOUBLE_CAST", "T_STRING_CAST", "T_ARRAY_CAST", "T_OBJECT_CAST", "T_BOOL_CAST", "T_UNSET_CAST", "'@'", "T_POW", "'['", "T_NEW", "T_CLONE", "T_EXIT", "T_IF", "T_ELSEIF", "T_ELSE", "T_ENDIF", "T_LNUMBER", "T_DNUMBER", "T_STRING", "T_STRING_VARNAME", "T_VARIABLE", "T_NUM_STRING", "T_INLINE_HTML", "T_ENCAPSED_AND_WHITESPACE", "T_CONSTANT_ENCAPSED_STRING", "T_ECHO", "T_DO", "T_WHILE", "T_ENDWHILE", "T_FOR", "T_ENDFOR", "T_FOREACH", "T_ENDFOREACH", "T_DECLARE", "T_ENDDECLARE", "T_AS", "T_SWITCH", "T_MATCH", "T_ENDSWITCH", "T_CASE", "T_DEFAULT", "T_BREAK", "T_CONTINUE", "T_GOTO", "T_FUNCTION", "T_FN", "T_CONST", "T_RETURN", "T_TRY", "T_CATCH", "T_FINALLY", "T_USE", "T_INSTEADOF", "T_GLOBAL", "T_STATIC", "T_ABSTRACT", "T_FINAL", "T_PRIVATE", "T_PROTECTED", "T_PUBLIC", "T_VAR", "T_UNSET", "T_ISSET", "T_EMPTY", "T_HALT_COMPILER", "T_CLASS", "T_TRAIT", "T_INTERFACE", "T_EXTENDS", "T_IMPLEMENTS", "T_OBJECT_OPERATOR", "T_NULLSAFE_OBJECT_OPERATOR", "T_LIST", "T_ARRAY", "T_CALLABLE", "T_CLASS_C", "T_TRAIT_C", "T_METHOD_C", "T_FUNC_C", "T_LINE", "T_FILE", "T_START_HEREDOC", "T_END_HEREDOC", "T_DOLLAR_OPEN_CURLY_BRACES", "T_CURLY_OPEN", "T_PAAMAYIM_NEKUDOTAYIM", "T_NAMESPACE", "T_NS_C", "T_DIR", "T_NS_SEPARATOR", "T_ELLIPSIS", "T_NAME_FULLY_QUALIFIED", "T_NAME_QUALIFIED", "T_NAME_RELATIVE", "T_ATTRIBUTE", "';'", "']'", "'{'", "'}'", "'('", "')'", "'`'", "'\"'", "'\$'"); + protected $tokenToSymbol = array(0, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 55, 163, 165, 164, 54, 37, 165, 160, 161, 52, 49, 8, 50, 51, 53, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 31, 156, 43, 16, 45, 30, 67, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 69, 165, 157, 36, 165, 162, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 158, 35, 159, 57, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 38, 39, 40, 41, 42, 44, 46, 47, 48, 56, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155); + protected $action = array(130, 131, 132, 552, 133, 134, 0, 698, 699, 700, 135, 36, 883, 528, 529, -32766, 1212, -32766, -32766, -32766, -551, 1145, 772, 889, 430, 431, 1232, -551, -32766, -32766, -32766, -293, -32766, 1231, -32766, 245, -32766, -189, -32766, -32766, -32766, -32766, -32766, 458, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 124, 783, 701, 777, -32766, 388, 1024, 1025, 1026, 1023, 1022, 1021, -32766, 428, 429, 955, 261, 136, 372, 705, 706, 707, 708, 391, -188, 397, 1024, 1025, 1026, 1023, 1022, 1021, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 739, 553, 740, 741, 742, 743, 731, 732, 373, 374, 734, 735, 720, 721, 722, 724, 725, 726, 333, 765, 766, 767, 768, 769, 727, 728, 554, 555, 760, 751, 749, 750, 746, 747, 778, 2, 556, 557, 745, 558, 559, 560, 561, 562, 563, -542, -548, 19, -502, -542, 748, 564, 565, -548, 137, -32766, -32766, -32766, 130, 131, 132, 552, 133, 134, 976, 698, 699, 700, 135, 36, -32766, -32766, -32766, -32766, 675, -32766, -32766, -32766, 80, 1145, 544, -551, -32766, -32766, 309, -551, -32766, -32766, -32766, -293, -32766, -32766, -32766, 245, -32766, -189, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 31, 433, 429, -32766, -32766, -502, -502, 701, 782, -32766, 388, 391, -32766, -32766, -32766, 235, 126, -32766, -82, 142, -502, 261, 136, 372, 705, 706, 707, 708, 247, -188, 397, 292, -502, -32766, -508, -32766, -32766, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 739, 553, 740, 741, 742, 743, 731, 732, 373, 374, 734, 735, 720, 721, 722, 724, 725, 726, 333, 765, 766, 767, 768, 769, 727, 728, 554, 555, 760, 751, 749, 750, 746, 747, 294, -82, 556, 557, 745, 558, 559, 560, 561, 562, 563, 310, 81, 82, 83, -548, 748, 564, 565, -548, 137, 723, 693, 694, 695, 696, 697, -32766, 698, 699, 700, 736, 737, 33, 307, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 322, 263, -32766, -32766, -32766, 104, 105, 106, 346, 263, 952, 951, 950, 107, 350, 438, 439, 701, -32766, -32766, -32766, 107, -253, -32766, 355, -32766, -32766, -32766, -32766, -32766, -32766, 702, 703, 704, 705, 706, 707, 708, 452, -32766, 770, -32766, -32766, -32766, -32766, -32766, 357, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 739, 762, 740, 741, 742, 743, 731, 732, 733, 761, 734, 735, 720, 721, 722, 724, 725, 726, 764, 765, 766, 767, 768, 769, 727, 728, 729, 730, 760, 751, 749, 750, 746, 747, 619, 24, 738, 744, 745, 752, 753, 755, 754, 756, 757, 524, -32766, -32766, -32766, 574, 748, 759, 758, 48, 49, 50, 483, 51, 52, 147, 397, 580, 408, 53, 54, 409, 55, -32766, 975, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, -32767, 865, -32767, -32767, -32767, -32767, 99, 100, 101, 102, 103, 1257, 410, 1172, 1258, 411, 1145, 865, 271, 634, 635, 56, 57, 148, 808, 1184, 809, 58, 453, 59, 240, 241, 60, 61, 62, 63, 64, 65, 66, 67, 787, 26, 262, 68, 412, 484, 121, 667, -32766, 1178, 1179, 485, 1143, 781, 1147, 1146, 1148, 1176, 40, 23, 486, 1002, 487, 150, 488, 234, 489, 962, 963, 490, 491, 780, 423, 424, 42, 43, 413, 417, 415, 865, 44, 492, 151, 855, 920, 248, 345, 321, 1152, 1147, 1146, 1148, 122, 781, 493, 494, 495, 152, -330, 855, -330, 127, -505, 960, 154, 496, 497, 35, 1166, 1167, 1168, 1169, 1163, 1164, 280, 146, 377, 26, -14, 128, 1170, 1165, 962, 963, 1147, 1146, 1148, 281, 141, 781, -501, 155, 69, 1176, 305, 306, 309, 34, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 156, -149, -149, -149, 478, 867, 18, 662, 1152, 1152, 855, 440, 441, -505, -505, 157, -149, 781, -149, 138, -149, 867, -149, 662, 808, 309, 809, 242, 1060, 1062, 496, 497, 414, 1166, 1167, 1168, 1169, 1163, 1164, -500, -505, -501, -501, -107, -107, 1170, 1165, -503, 1228, 865, 611, 612, 841, -107, -107, -107, -501, 71, 921, -84, 306, 309, -107, -32766, -76, 1001, -49, 686, -501, 1145, -507, -73, -71, 774, -70, -69, -32766, -32766, -32766, 668, -32766, -68, -32766, 867, -32766, 662, -149, -32766, 781, 781, -67, 281, -32766, -32766, -32766, -66, 73, -65, -32766, -32766, 309, -500, -500, 129, -32766, 388, -64, -45, -32766, -503, -503, -16, -32766, 145, 1145, 264, -500, 676, 865, 679, 864, -32766, -32766, -32766, -503, -32766, 772, -32766, -500, -32766, 144, 855, -32766, 272, -107, 273, -503, -32766, -32766, -32766, 879, 72, 244, -32766, -32766, -32766, 275, 776, 669, -32766, 388, 1145, 664, 865, -500, 274, 276, -32766, -32766, -32766, -32766, 315, -32766, 281, -32766, 263, -32766, 73, 73, -32766, 107, 309, 309, 143, -32766, -32766, -32766, 642, -32766, 246, -32766, -32766, 532, 671, 1145, 772, -32766, 388, -4, 865, 1259, -32766, -32766, -32766, -32766, -32766, 781, -32766, -32766, -32766, 855, 1030, -32766, 865, 867, 139, 662, -32766, -32766, -32766, 655, 309, 865, -32766, -32766, -32766, -500, -500, 526, -32766, 388, 1145, 101, 102, 103, 620, 637, -32766, -32766, -32766, -32766, -500, -32766, 960, -32766, 855, -32766, 20, 865, -32766, -32766, 625, 677, -500, -32766, -32766, -32766, 435, -32766, 463, -32766, -32766, 962, 963, 1145, 626, -32766, 388, 638, 962, 963, -32766, -32766, -32766, -32766, -32766, 609, -32766, 289, -32766, 46, 855, -32766, 906, 407, 662, -32766, -32766, -32766, -32766, 287, 1016, 1183, -32766, -32766, 855, 286, 293, 781, -32766, 388, 1247, 890, 414, 855, 402, 891, -32766, 881, 538, 279, -231, -231, -231, -107, -107, 1000, 414, 867, 26, 662, 1185, 578, 800, -107, -107, -107, -466, -107, -107, 855, 781, 47, -456, 7, 1176, 22, 841, -107, -107, -107, 348, 282, 283, 780, 9, -230, -230, -230, 281, 1173, -536, 414, 38, 867, 39, 662, -4, 683, 684, 846, 32, 243, -107, -107, 930, 907, 680, 867, 123, 662, -231, 841, -107, -107, -107, 914, 867, 904, 662, 915, 844, 902, 1005, 497, 1008, 1166, 1167, 1168, 1169, 1163, 1164, 1009, 1006, 284, 285, 1007, 1013, 1170, 1165, 792, 1198, 1216, 867, 30, 662, -230, 304, 1250, 349, 71, 614, 842, 306, 309, 347, 663, 666, 670, 672, -107, 125, -107, 673, 674, 678, 665, 288, 1254, 1256, -107, -107, -107, -107, -107, -107, -107, 803, 802, 811, 888, 922, 810, 1255, 887, 886, 1131, 874, 882, 872, 912, 913, 1253, 1210, 1199, 1217, 1223, 1226, 0, -534, -508, -507, -506, 1, 27, 28, 37, 41, 45, 70, 74, 75, 76, 77, -307, -256, 78, 79, 140, 149, 153, 239, 311, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 403, 404, 0, -254, -253, 12, 13, 14, 15, 17, 376, 454, 455, 462, 465, 466, 467, 468, 472, 473, 474, 481, 649, 1156, 1099, 1174, 977, 1135, -258, -99, 11, 16, 25, 278, 375, 571, 575, 601, 654, 1103, 1151, 1100, 1229, 0, -470, 1116, 0, 1177, 0, 309); + protected $actionCheck = array(2, 3, 4, 5, 6, 7, 0, 9, 10, 11, 12, 13, 1, 116, 117, 73, 1, 9, 10, 11, 1, 79, 79, 126, 127, 128, 1, 8, 86, 87, 88, 8, 90, 8, 92, 37, 94, 8, 30, 97, 32, 33, 34, 101, 102, 103, 104, 9, 10, 11, 108, 109, 14, 1, 56, 79, 114, 115, 115, 116, 117, 118, 119, 120, 122, 105, 106, 1, 70, 71, 72, 73, 74, 75, 76, 115, 8, 79, 115, 116, 117, 118, 119, 120, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 153, 8, 133, 134, 135, 136, 137, 138, 139, 140, 141, 157, 1, 8, 69, 161, 147, 148, 149, 8, 151, 9, 10, 11, 2, 3, 4, 5, 6, 7, 161, 9, 10, 11, 12, 13, 9, 10, 11, 73, 158, 9, 10, 11, 158, 79, 80, 157, 9, 10, 164, 161, 86, 87, 88, 161, 90, 30, 92, 37, 94, 161, 30, 97, 32, 33, 34, 35, 102, 103, 104, 8, 105, 106, 108, 109, 131, 132, 56, 156, 114, 115, 115, 9, 10, 11, 14, 8, 122, 31, 8, 146, 70, 71, 72, 73, 74, 75, 76, 8, 161, 79, 8, 158, 30, 160, 32, 33, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 8, 96, 133, 134, 135, 136, 137, 138, 139, 140, 141, 69, 9, 10, 11, 157, 147, 148, 149, 161, 151, 2, 3, 4, 5, 6, 7, 9, 9, 10, 11, 12, 13, 30, 8, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 8, 56, 9, 10, 11, 52, 53, 54, 8, 56, 118, 119, 120, 68, 8, 131, 132, 56, 9, 10, 11, 68, 161, 30, 8, 32, 33, 34, 35, 36, 37, 70, 71, 72, 73, 74, 75, 76, 31, 30, 79, 32, 33, 34, 35, 36, 8, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 74, 75, 133, 134, 135, 136, 137, 138, 139, 140, 141, 84, 9, 10, 11, 1, 147, 148, 149, 2, 3, 4, 5, 6, 7, 14, 79, 50, 8, 12, 13, 8, 15, 30, 1, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 1, 43, 44, 45, 46, 47, 48, 49, 50, 51, 79, 8, 1, 82, 8, 79, 1, 30, 74, 75, 49, 50, 14, 105, 143, 107, 55, 158, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 8, 69, 70, 71, 72, 73, 16, 31, 115, 77, 78, 79, 115, 81, 152, 153, 154, 85, 86, 87, 88, 159, 90, 14, 92, 96, 94, 134, 135, 97, 98, 152, 105, 106, 102, 103, 104, 105, 106, 1, 108, 109, 14, 83, 31, 37, 114, 115, 1, 152, 153, 154, 16, 81, 122, 123, 124, 14, 105, 83, 107, 16, 69, 115, 14, 133, 134, 14, 136, 137, 138, 139, 140, 141, 142, 100, 101, 69, 31, 16, 148, 149, 134, 135, 152, 153, 154, 155, 16, 81, 69, 16, 160, 85, 162, 163, 164, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 16, 74, 75, 76, 105, 156, 107, 158, 1, 1, 83, 105, 106, 131, 132, 16, 89, 81, 91, 158, 93, 156, 95, 158, 105, 164, 107, 37, 58, 59, 133, 134, 105, 136, 137, 138, 139, 140, 141, 69, 158, 131, 132, 116, 117, 148, 149, 69, 1, 1, 110, 111, 125, 126, 127, 128, 146, 160, 156, 31, 163, 164, 126, 73, 31, 156, 31, 158, 158, 79, 160, 31, 31, 79, 31, 31, 86, 87, 88, 31, 90, 31, 92, 156, 94, 158, 159, 97, 81, 81, 31, 155, 102, 103, 104, 31, 160, 31, 108, 109, 164, 131, 132, 31, 114, 115, 31, 31, 73, 131, 132, 31, 122, 31, 79, 31, 146, 31, 1, 31, 31, 86, 87, 88, 146, 90, 79, 92, 158, 94, 31, 83, 97, 35, 126, 35, 158, 102, 103, 104, 37, 151, 37, 108, 109, 73, 35, 153, 31, 114, 115, 79, 158, 1, 69, 30, 35, 122, 86, 87, 88, 35, 90, 155, 92, 56, 94, 160, 160, 97, 68, 164, 164, 69, 102, 103, 104, 76, 73, 37, 108, 109, 88, 31, 79, 79, 114, 115, 0, 1, 82, 86, 87, 88, 122, 90, 81, 92, 84, 94, 83, 81, 97, 1, 156, 158, 158, 102, 103, 104, 91, 164, 1, 108, 109, 73, 131, 132, 84, 114, 115, 79, 49, 50, 51, 89, 93, 122, 86, 87, 88, 146, 90, 115, 92, 83, 94, 96, 1, 97, 115, 95, 31, 158, 102, 103, 104, 96, 73, 96, 108, 109, 134, 135, 79, 99, 114, 115, 99, 134, 135, 86, 87, 88, 122, 90, 112, 92, 113, 94, 69, 83, 97, 156, 126, 158, 115, 102, 103, 104, 130, 121, 143, 108, 109, 83, 129, 129, 81, 114, 115, 84, 126, 105, 83, 107, 126, 122, 151, 150, 112, 99, 100, 101, 116, 117, 1, 105, 156, 69, 158, 143, 150, 125, 126, 127, 128, 146, 116, 117, 83, 81, 69, 146, 146, 85, 146, 125, 126, 127, 128, 146, 131, 132, 152, 147, 99, 100, 101, 155, 157, 160, 105, 156, 156, 156, 158, 159, 156, 156, 156, 144, 145, 116, 117, 156, 156, 159, 156, 158, 158, 159, 125, 126, 127, 128, 156, 156, 156, 158, 156, 156, 156, 156, 134, 156, 136, 137, 138, 139, 140, 141, 156, 156, 131, 132, 156, 156, 148, 149, 157, 157, 157, 156, 158, 158, 159, 158, 157, 146, 160, 157, 159, 163, 164, 158, 158, 158, 158, 158, 105, 158, 107, 158, 158, 158, 158, 112, 159, 159, 115, 116, 117, 118, 119, 120, 121, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, -1, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 159, 161, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, -1, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, -1, 162, 162, -1, 163, -1, 164); + protected $actionBase = array(0, -2, 151, 555, 816, 830, 865, 489, 379, 622, 858, 676, 780, 780, 839, 780, 493, 745, 301, 301, -57, 301, 301, 477, 477, 477, 618, 618, 618, 618, -58, -58, 95, 700, 733, 770, 663, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 803, 52, 530, 446, 570, 984, 990, 986, 991, 982, 981, 985, 987, 992, 911, 912, 727, 913, 914, 915, 916, 988, 872, 983, 989, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 300, 38, 168, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 156, 156, 156, 203, 525, 525, 8, 598, 161, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 349, 333, 435, 435, 435, 435, 435, 436, 436, 436, 436, 933, 564, 636, 635, 465, 470, 801, 801, 753, 753, 788, 746, 746, 746, 410, 410, 410, 74, 538, 396, 359, 414, 675, 675, 675, 675, 414, 414, 414, 414, 796, 996, 414, 414, 414, -103, 606, 713, 713, 881, 293, 293, 293, 713, 547, 762, 835, 547, 835, 15, 409, 789, -40, 96, -17, 789, 510, 829, 140, 19, 810, 444, 810, 742, 859, 886, 993, 232, 784, 909, 787, 910, 224, 661, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 979, 997, 980, -24, 997, 997, 997, 568, -24, 358, 422, -24, 754, 980, 52, 805, 52, 52, 52, 52, 941, 52, 52, 52, 52, 52, 52, 946, 708, 704, 668, 347, 52, 530, 11, 11, 537, 66, 11, 11, 11, 11, 52, 52, 444, 737, 777, 534, 790, 68, 737, 737, 737, 187, 23, 201, 29, 527, 734, 734, 731, 748, 921, 921, 734, 743, 734, 748, 926, 734, 731, 731, 921, 731, 812, 208, 452, 332, 346, 731, 731, 455, 921, 223, 731, 731, 734, 734, 734, 731, 481, 734, 220, 211, 734, 734, 731, 731, 785, 786, 122, 921, 921, 921, 786, 340, 778, 778, 820, 821, 782, 712, 308, 274, 509, 192, 731, 712, 712, 734, 356, 782, 712, 782, 712, 775, 712, 712, 712, 782, 712, 743, 378, 712, 731, 484, 134, 712, 6, 927, 928, 656, 929, 924, 930, 952, 931, 934, 876, 939, 925, 935, 923, 922, 717, 507, 553, 806, 799, 920, 730, 730, 730, 918, 730, 730, 730, 730, 730, 730, 730, 730, 507, 811, 813, 776, 722, 942, 562, 580, 767, 871, 994, 995, 794, 798, 941, 974, 936, 815, 589, 960, 943, 826, 867, 944, 945, 961, 975, 976, 887, 732, 888, 896, 861, 947, 877, 730, 927, 934, 925, 935, 923, 922, 703, 694, 687, 692, 678, 672, 669, 671, 710, 917, 809, 862, 946, 919, 507, 863, 956, 864, 962, 963, 875, 779, 736, 869, 897, 948, 949, 950, 878, 977, 817, 957, 932, 964, 781, 898, 965, 966, 967, 968, 899, 879, 883, 822, 764, 954, 774, 900, 443, 739, 749, 953, 486, 940, 884, 901, 902, 969, 970, 971, 903, 937, 827, 958, 761, 959, 955, 828, 838, 526, 726, 728, 545, 560, 904, 905, 938, 714, 729, 840, 842, 978, 906, 567, 843, 592, 907, 973, 612, 627, 747, 885, 808, 783, 769, 951, 716, 844, 908, 845, 847, 854, 972, 855, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 449, 449, 449, 449, 449, 449, 301, 301, 301, 301, 449, 449, 449, 449, 449, 449, 449, 0, 0, 301, 0, 0, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 285, 414, 414, 285, 0, 285, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 285, 285, 285, 285, 285, 285, 285, 293, 293, 293, 293, 812, 414, 414, 414, 414, -37, 293, 293, 414, 414, -37, 414, 414, 414, 414, 414, 414, 0, 0, -24, 835, 0, 743, 743, 743, 743, 0, 0, 0, 0, 835, 835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -24, 835, 0, -24, 0, 743, 743, 414, 812, 812, 25, 414, 0, 0, 0, 0, -24, 743, -24, 835, 11, 52, 25, 0, 492, 492, 492, 492, 0, 444, 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, 812, 743, 812, 0, 743, 743, 743, 0, 0, 0, 0, 0, 743, 731, 0, 921, 0, 0, 0, 0, 734, 0, 0, 0, 0, 0, 0, 734, 926, 731, 731, 0, 0, 0, 0, 0, 0, 743, 0, 0, 0, 0, 0, 0, 0, 730, 779, 0, 779, 0, 730, 730, 730); + protected $actionDefault = array(3, 32767, 99, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 97, 32767, 32767, 32767, 32767, 32767, 32767, 554, 554, 554, 554, 235, 99, 32767, 32767, 32767, 32767, 430, 349, 349, 349, 32767, 32767, 498, 498, 498, 498, 498, 498, 32767, 32767, 32767, 32767, 32767, 32767, 430, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 97, 32767, 32767, 32767, 35, 5, 6, 8, 9, 48, 15, 32767, 32767, 32767, 32767, 32767, 99, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 547, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 434, 413, 414, 416, 417, 348, 499, 553, 292, 550, 347, 142, 304, 294, 223, 295, 239, 240, 266, 344, 146, 378, 431, 380, 429, 433, 379, 354, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 352, 353, 432, 435, 436, 439, 440, 410, 409, 408, 376, 32767, 32767, 377, 351, 381, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 99, 32767, 383, 382, 399, 400, 397, 398, 401, 402, 403, 404, 405, 32767, 32767, 32767, 32767, 32767, 327, 390, 391, 283, 283, 329, 32767, 32767, 32767, 32767, 32767, 32767, 492, 407, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 99, 32767, 97, 32767, 494, 373, 375, 462, 385, 386, 384, 355, 32767, 469, 32767, 99, 471, 32767, 32767, 32767, 108, 32767, 32767, 32767, 493, 32767, 500, 500, 32767, 455, 97, 32767, 32767, 32767, 32767, 261, 32767, 32767, 32767, 32767, 561, 455, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 32767, 107, 32767, 32767, 32767, 97, 185, 32767, 249, 251, 99, 515, 190, 32767, 474, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 467, 190, 190, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 455, 395, 135, 32767, 135, 500, 387, 388, 389, 457, 500, 500, 500, 32767, 32767, 32767, 190, 32767, 472, 472, 97, 97, 97, 97, 467, 32767, 190, 190, 32767, 190, 108, 96, 96, 96, 96, 190, 190, 96, 100, 98, 190, 190, 32767, 32767, 32767, 190, 96, 32767, 98, 98, 32767, 32767, 190, 190, 206, 204, 98, 32767, 519, 520, 204, 98, 208, 208, 228, 228, 446, 285, 98, 96, 98, 98, 190, 285, 285, 32767, 98, 446, 285, 446, 285, 192, 285, 285, 285, 446, 285, 32767, 98, 285, 190, 96, 96, 285, 32767, 32767, 32767, 457, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 487, 32767, 504, 517, 393, 394, 396, 502, 418, 419, 420, 421, 422, 423, 424, 426, 549, 32767, 461, 32767, 32767, 32767, 32767, 303, 559, 32767, 559, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 560, 32767, 500, 32767, 32767, 32767, 32767, 392, 7, 74, 41, 42, 50, 56, 478, 479, 480, 481, 475, 476, 482, 477, 32767, 483, 525, 32767, 32767, 501, 552, 32767, 32767, 32767, 32767, 32767, 32767, 135, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 487, 32767, 133, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 500, 32767, 32767, 32767, 280, 282, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 500, 32767, 32767, 32767, 268, 270, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 265, 32767, 32767, 343, 32767, 32767, 32767, 32767, 323, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 148, 148, 3, 3, 306, 148, 148, 148, 306, 148, 306, 306, 148, 148, 148, 148, 148, 148, 180, 243, 246, 228, 228, 148, 315, 148); + protected $goto = array(190, 190, 650, 1020, 979, 399, 624, 798, 1019, 658, 393, 297, 298, 318, 546, 303, 398, 319, 400, 603, 362, 366, 531, 569, 573, 161, 161, 161, 161, 187, 187, 171, 173, 209, 191, 204, 187, 187, 187, 187, 187, 188, 188, 188, 188, 188, 188, 182, 183, 184, 185, 186, 206, 204, 207, 504, 505, 389, 506, 508, 509, 510, 511, 512, 513, 514, 515, 1046, 162, 163, 164, 189, 165, 166, 167, 160, 168, 169, 170, 172, 203, 205, 208, 230, 233, 236, 238, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 266, 267, 300, 301, 302, 394, 395, 396, 551, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 174, 225, 175, 192, 193, 194, 231, 182, 183, 184, 185, 186, 206, 1046, 195, 176, 177, 178, 196, 192, 179, 232, 197, 159, 198, 226, 180, 199, 227, 228, 181, 229, 200, 201, 202, 312, 312, 312, 312, 801, 577, 591, 594, 595, 596, 597, 615, 616, 617, 660, 799, 329, 530, 521, 590, 590, 568, 794, 794, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 1175, 858, 779, 859, 806, 775, 854, 849, 850, 863, 905, 807, 851, 804, 852, 853, 805, 295, 295, 295, 295, 832, 857, 607, 607, 364, 521, 773, 530, 969, 966, 967, 996, 997, 539, 540, 957, 964, 965, 371, 549, 588, 621, 779, 570, 779, 1244, 1244, 1193, 1193, 543, 584, 585, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 1193, 326, 1244, 1144, 1144, 1144, 961, 1140, 1233, 469, 961, 961, 926, 961, 961, 961, 961, 961, 961, 1225, 1225, 1225, 1225, 1144, 470, 360, 471, 21, 1144, 1144, 1144, 1144, 477, 794, 1144, 1144, 1144, 332, 437, 437, 567, 1012, 618, 661, 632, 633, 542, 332, 332, 437, 623, 647, 647, 870, 653, 1010, 1094, 871, 447, 1218, 1219, 814, 332, 332, 1141, 332, 826, 1260, 5, 813, 6, 518, 518, 518, 789, 320, 1191, 1191, 523, 791, 332, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 1191, 426, 405, 1142, 1201, 1202, 899, 899, 899, 899, 370, 536, 426, 893, 900, 897, 380, 657, 583, 507, 507, 308, 291, 1204, 507, 507, 507, 507, 507, 507, 507, 507, 507, 507, 1243, 1243, 516, 516, 516, 516, 1220, 1221, 819, 875, 1034, 572, 547, 582, 643, 522, 534, 587, 1243, 816, 948, 522, 945, 534, 685, 985, 363, 330, 331, 818, 828, 627, 924, 1246, 392, 1137, 579, 812, 418, 418, 418, 448, 523, 550, 442, 443, 989, 1029, 824, 1136, 910, 1251, 1252, 451, 600, 537, 1215, 1215, 1215, 682, 602, 604, 0, 622, 0, 0, 640, 644, 940, 648, 656, 936, 0, 0, 797, 0, 822, 1227, 1227, 1227, 1227, 929, 903, 903, 901, 903, 681, 0, 270, 519, 519, 0, 0, 520, 938, 933, 0, 827, 815, 984, 0, 0, 988, 0, 1211, 0, 0, 0, 1139, 0, 0, 908, 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, 418, 0, 418, 0, 378, 379, 0, 0, 0, 630, 0, 631, 898, 382, 383, 384, 0, 641, 987, 0, 385, 1213, 1213, 987, 324, 1125, 884, 0, 0, 1126, 1129, 885, 1130, 0, 1027, 831, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 943, 943); + protected $gotoCheck = array(41, 41, 71, 128, 111, 64, 64, 25, 128, 8, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 57, 57, 57, 57, 57, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 22, 22, 22, 22, 14, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 26, 88, 74, 74, 99, 99, 114, 21, 21, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 63, 11, 63, 14, 6, 14, 14, 14, 14, 48, 14, 14, 14, 14, 14, 14, 23, 23, 23, 23, 44, 14, 107, 107, 74, 74, 5, 74, 107, 107, 107, 14, 14, 74, 74, 105, 105, 105, 74, 74, 54, 54, 11, 74, 11, 165, 165, 152, 152, 154, 74, 74, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 161, 165, 71, 71, 71, 71, 19, 163, 74, 71, 71, 94, 71, 71, 71, 71, 71, 71, 8, 8, 8, 8, 71, 139, 60, 139, 74, 71, 71, 71, 71, 139, 21, 71, 71, 71, 13, 133, 133, 7, 7, 82, 7, 82, 82, 95, 13, 13, 133, 62, 7, 7, 71, 7, 7, 135, 71, 158, 158, 158, 34, 13, 13, 19, 13, 34, 13, 45, 34, 45, 18, 18, 18, 19, 28, 153, 153, 13, 17, 13, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 18, 103, 19, 19, 19, 18, 18, 18, 18, 27, 8, 18, 18, 18, 84, 84, 84, 8, 155, 155, 151, 151, 13, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 164, 164, 98, 98, 98, 98, 160, 160, 38, 16, 16, 98, 2, 2, 13, 8, 8, 16, 164, 36, 101, 8, 16, 8, 90, 113, 8, 88, 88, 16, 40, 16, 16, 164, 12, 144, 12, 16, 22, 22, 22, 141, 13, 8, 8, 8, 116, 131, 8, 16, 87, 8, 8, 80, 81, 47, 114, 114, 114, 47, 47, 47, -1, 47, -1, -1, 47, 47, 47, 47, 47, 47, -1, -1, 24, -1, 8, 114, 114, 114, 114, 24, 24, 24, 24, 24, 24, -1, 23, 23, 23, -1, -1, 24, 24, 24, -1, 15, 15, 15, -1, -1, 15, -1, 114, -1, -1, -1, 13, -1, -1, 15, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, -1, 22, -1, 78, 78, -1, -1, -1, 78, -1, 78, 15, 78, 78, 78, -1, 78, 114, -1, 78, 114, 114, 114, 78, 76, 76, -1, -1, 76, 76, 76, 76, -1, 15, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 98, 98); + protected $gotoBase = array(0, 0, -276, 0, 0, 197, 186, 285, -11, 0, 0, -87, 90, 9, -164, 53, -51, 39, 62, -100, 0, -133, 154, 204, 446, 3, 168, 32, 48, 0, 0, 0, 0, 0, -34, 0, 73, 0, 77, 0, -2, -1, 0, 0, 192, -365, 0, -232, 183, 0, 0, 0, 0, 0, 193, 0, 0, -23, 0, 0, 237, 0, 67, 178, -229, 0, 0, 0, 0, 0, 0, -6, 0, 0, -199, 0, 145, -173, 41, 0, -19, -21, -376, 0, 70, 0, 0, 16, -280, 0, 23, 0, 0, 0, 233, 257, 0, 0, 352, -58, 0, 50, 0, 75, 0, -45, 0, -55, 0, 0, 0, 2, 0, 51, 171, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -262, 0, 0, 12, 0, 260, 0, 45, 0, 0, 0, -189, 0, 10, 0, 0, 7, 0, 0, 0, 0, 0, 0, 58, 4, 94, 213, 127, 0, 0, 27, 0, 34, 225, 0, 231, 86, -54, 0, 0); + protected $gotoDefault = array(-32768, 482, 689, 4, 690, 763, 771, 566, 498, 659, 325, 592, 390, 1209, 856, 1033, 548, 790, 1153, 1161, 427, 793, 313, 327, 838, 839, 840, 367, 352, 358, 365, 613, 593, 464, 825, 421, 817, 456, 820, 420, 829, 158, 387, 480, 833, 3, 835, 525, 866, 353, 843, 354, 636, 845, 533, 847, 848, 361, 368, 369, 1038, 541, 589, 860, 237, 535, 861, 351, 862, 869, 356, 359, 645, 436, 475, 381, 1014, 576, 610, 432, 450, 599, 598, 586, 895, 457, 434, 909, 328, 917, 687, 1045, 605, 459, 925, 606, 932, 935, 499, 500, 449, 947, 268, 460, 974, 628, 629, 959, 608, 972, 444, 978, 422, 986, 1197, 425, 990, 260, 993, 269, 386, 401, 998, 999, 8, 1004, 651, 652, 10, 265, 479, 1028, 646, 419, 1044, 406, 1113, 1115, 527, 461, 1133, 1132, 639, 476, 1138, 1200, 416, 501, 445, 299, 502, 290, 316, 296, 517, 277, 317, 503, 446, 1206, 1214, 314, 29, 1234, 1245, 323, 545, 581); + protected $ruleToNonTerminal = array(0, 1, 3, 3, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 8, 9, 10, 10, 10, 11, 11, 12, 12, 13, 14, 14, 15, 15, 16, 16, 17, 17, 20, 20, 21, 22, 22, 23, 23, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 28, 28, 29, 29, 31, 33, 33, 27, 35, 35, 32, 37, 37, 34, 34, 36, 36, 38, 38, 30, 39, 39, 40, 42, 43, 43, 44, 45, 45, 47, 46, 46, 46, 46, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 24, 24, 67, 67, 70, 70, 69, 68, 68, 61, 73, 73, 74, 74, 75, 75, 76, 76, 25, 25, 26, 26, 26, 79, 79, 79, 80, 80, 83, 83, 81, 81, 84, 85, 85, 55, 55, 63, 63, 66, 66, 66, 65, 86, 86, 87, 56, 56, 56, 56, 88, 88, 89, 89, 90, 90, 91, 92, 92, 93, 93, 94, 94, 53, 53, 49, 49, 96, 51, 51, 97, 50, 50, 52, 52, 62, 62, 62, 62, 77, 77, 100, 100, 102, 102, 102, 102, 101, 101, 101, 104, 104, 104, 105, 105, 107, 107, 107, 106, 106, 108, 108, 109, 109, 109, 103, 103, 78, 78, 78, 19, 19, 110, 110, 111, 111, 111, 111, 58, 112, 112, 113, 59, 115, 115, 116, 116, 117, 117, 82, 118, 118, 118, 118, 118, 123, 123, 124, 124, 125, 125, 125, 125, 125, 126, 127, 127, 122, 122, 119, 119, 121, 121, 129, 129, 128, 128, 128, 128, 128, 128, 120, 130, 130, 132, 131, 131, 60, 95, 133, 133, 54, 54, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 140, 134, 134, 139, 139, 142, 143, 143, 144, 145, 145, 145, 18, 18, 71, 71, 71, 71, 135, 135, 135, 135, 147, 147, 136, 136, 138, 138, 138, 141, 141, 152, 152, 152, 152, 152, 152, 152, 152, 152, 153, 153, 99, 155, 155, 155, 155, 137, 137, 137, 137, 137, 137, 137, 137, 57, 57, 150, 150, 150, 150, 156, 156, 146, 146, 146, 157, 157, 157, 157, 157, 157, 72, 72, 64, 64, 64, 64, 114, 114, 114, 114, 160, 159, 149, 149, 149, 149, 149, 149, 149, 148, 148, 148, 158, 158, 158, 158, 98, 154, 162, 162, 161, 161, 163, 163, 163, 163, 163, 163, 163, 163, 151, 151, 151, 151, 165, 166, 164, 164, 164, 164, 164, 164, 164, 164, 167, 167, 167, 167); + protected $ruleToLength = array(1, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 2, 1, 3, 4, 1, 2, 0, 1, 1, 1, 1, 1, 3, 5, 4, 3, 4, 2, 3, 1, 1, 7, 6, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 3, 1, 3, 1, 2, 2, 3, 1, 3, 2, 3, 1, 3, 2, 0, 1, 1, 1, 1, 1, 3, 7, 10, 5, 7, 9, 5, 3, 3, 3, 3, 3, 3, 1, 2, 5, 7, 9, 6, 5, 6, 3, 2, 1, 1, 1, 0, 2, 1, 3, 8, 0, 4, 2, 1, 3, 0, 1, 0, 1, 3, 1, 8, 9, 8, 7, 6, 1, 2, 2, 0, 2, 0, 2, 0, 2, 2, 1, 3, 1, 4, 1, 4, 1, 1, 4, 2, 1, 3, 3, 3, 4, 4, 5, 0, 2, 4, 3, 1, 1, 7, 0, 2, 1, 3, 3, 4, 1, 4, 0, 2, 5, 0, 2, 6, 0, 2, 0, 3, 1, 2, 1, 1, 2, 0, 1, 3, 0, 1, 1, 1, 6, 8, 6, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 1, 2, 1, 0, 1, 0, 2, 2, 2, 4, 1, 3, 1, 2, 2, 3, 2, 3, 1, 1, 2, 3, 1, 1, 3, 2, 0, 1, 5, 5, 10, 3, 1, 1, 3, 0, 2, 4, 5, 4, 4, 4, 3, 1, 1, 1, 1, 1, 1, 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 3, 1, 1, 3, 2, 2, 3, 1, 0, 1, 1, 3, 3, 3, 4, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 3, 4, 4, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 2, 1, 2, 4, 2, 2, 8, 9, 8, 9, 9, 10, 9, 10, 8, 3, 2, 0, 4, 2, 1, 3, 2, 2, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 0, 3, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 4, 1, 1, 3, 1, 1, 1, 1, 1, 3, 2, 3, 0, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 4, 4, 1, 4, 4, 0, 1, 1, 1, 3, 3, 1, 4, 2, 2, 1, 3, 1, 4, 4, 3, 3, 3, 3, 1, 3, 1, 1, 3, 1, 1, 4, 1, 1, 1, 3, 1, 1, 2, 1, 3, 4, 3, 2, 0, 2, 2, 1, 2, 1, 1, 1, 4, 3, 3, 3, 3, 6, 3, 1, 1, 2, 1); + protected function initReduceCallbacks() + { + $this->reduceCallbacks = [0 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 1 => function ($stackPos) { + $this->semValue = $this->handleNamespaces($this->semStack[$stackPos - (1 - 1)]); + }, 2 => function ($stackPos) { + if (\is_array($this->semStack[$stackPos - (2 - 2)])) { + $this->semValue = \array_merge($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); + } else { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } + }, 3 => function ($stackPos) { + $this->semValue = array(); + }, 4 => function ($stackPos) { + $startAttributes = $this->lookaheadStartAttributes; + if (isset($startAttributes['comments'])) { + $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); + } else { + $nop = null; + } + if ($nop !== null) { + $this->semStack[$stackPos - (1 - 1)][] = $nop; + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 5 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 6 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 7 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 8 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 9 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 10 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 11 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 12 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 13 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 14 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 15 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 16 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 17 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 18 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 19 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 20 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 21 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 22 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 23 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 24 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 25 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 26 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 27 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 28 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 29 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 30 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 31 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 32 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 33 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 34 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 35 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 36 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 37 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 38 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 39 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 40 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 41 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 42 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 43 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 44 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 45 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 46 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 47 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 48 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 49 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 50 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 51 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 52 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 53 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 54 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 55 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 56 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 57 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 58 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 59 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 60 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 61 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 62 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 63 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 64 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 65 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 66 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 67 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 68 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 69 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 70 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 71 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 72 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 73 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 74 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 75 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 76 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 77 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 78 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 79 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 80 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 81 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 82 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 83 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 84 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 85 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 86 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 87 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 88 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 89 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 90 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 91 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 92 => function ($stackPos) { + $this->semValue = new Name(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 93 => function ($stackPos) { + $this->semValue = new Expr\Variable(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 94 => function ($stackPos) { + /* nothing */ + }, 95 => function ($stackPos) { + /* nothing */ + }, 96 => function ($stackPos) { + /* nothing */ + }, 97 => function ($stackPos) { + $this->emitError(new Error('A trailing comma is not allowed here', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes)); + }, 98 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 99 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 100 => function ($stackPos) { + $this->semValue = new Node\Attribute($this->semStack[$stackPos - (1 - 1)], [], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 101 => function ($stackPos) { + $this->semValue = new Node\Attribute($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 102 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 103 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 104 => function ($stackPos) { + $this->semValue = new Node\AttributeGroup($this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 105 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 106 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 107 => function ($stackPos) { + $this->semValue = []; + }, 108 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 109 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 110 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 111 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 112 => function ($stackPos) { + $this->semValue = new Stmt\HaltCompiler($this->lexer->handleHaltCompiler(), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 113 => function ($stackPos) { + $this->semValue = new Stmt\Namespace_($this->semStack[$stackPos - (3 - 2)], null, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON); + $this->checkNamespace($this->semValue); + }, 114 => function ($stackPos) { + $this->semValue = new Stmt\Namespace_($this->semStack[$stackPos - (5 - 2)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $this->checkNamespace($this->semValue); + }, 115 => function ($stackPos) { + $this->semValue = new Stmt\Namespace_(null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $this->checkNamespace($this->semValue); + }, 116 => function ($stackPos) { + $this->semValue = new Stmt\Use_($this->semStack[$stackPos - (3 - 2)], Stmt\Use_::TYPE_NORMAL, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 117 => function ($stackPos) { + $this->semValue = new Stmt\Use_($this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 118 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 119 => function ($stackPos) { + $this->semValue = new Stmt\Const_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 120 => function ($stackPos) { + $this->semValue = Stmt\Use_::TYPE_FUNCTION; + }, 121 => function ($stackPos) { + $this->semValue = Stmt\Use_::TYPE_CONSTANT; + }, 122 => function ($stackPos) { + $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 6)], $this->semStack[$stackPos - (7 - 2)], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 123 => function ($stackPos) { + $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 5)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 124 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 125 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 126 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 127 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 128 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 129 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 130 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 131 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 132 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 133 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (1 - 1)); + }, 134 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (3 - 3)); + }, 135 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (1 - 1)); + }, 136 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (3 - 3)); + }, 137 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + $this->semValue->type = Stmt\Use_::TYPE_NORMAL; + }, 138 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue->type = $this->semStack[$stackPos - (2 - 1)]; + }, 139 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 140 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 141 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 142 => function ($stackPos) { + $this->semValue = new Node\Const_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 143 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 144 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 145 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 146 => function ($stackPos) { + $this->semValue = new Node\Const_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 147 => function ($stackPos) { + if (\is_array($this->semStack[$stackPos - (2 - 2)])) { + $this->semValue = \array_merge($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); + } else { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } + }, 148 => function ($stackPos) { + $this->semValue = array(); + }, 149 => function ($stackPos) { + $startAttributes = $this->lookaheadStartAttributes; + if (isset($startAttributes['comments'])) { + $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); + } else { + $nop = null; + } + if ($nop !== null) { + $this->semStack[$stackPos - (1 - 1)][] = $nop; + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 150 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 151 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 152 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 153 => function ($stackPos) { + throw new Error('__HALT_COMPILER() can only be used from the outermost scope', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 154 => function ($stackPos) { + if ($this->semStack[$stackPos - (3 - 2)]) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + $attrs = $this->startAttributeStack[$stackPos - (3 - 1)]; + $stmts = $this->semValue; + if (!empty($attrs['comments'])) { + $stmts[0]->setAttribute('comments', \array_merge($attrs['comments'], $stmts[0]->getAttribute('comments', []))); + } + } else { + $startAttributes = $this->startAttributeStack[$stackPos - (3 - 1)]; + if (isset($startAttributes['comments'])) { + $this->semValue = new Stmt\Nop($startAttributes + $this->endAttributes); + } else { + $this->semValue = null; + } + if (null === $this->semValue) { + $this->semValue = array(); + } + } + }, 155 => function ($stackPos) { + $this->semValue = new Stmt\If_($this->semStack[$stackPos - (7 - 3)], ['stmts' => \is_array($this->semStack[$stackPos - (7 - 5)]) ? $this->semStack[$stackPos - (7 - 5)] : array($this->semStack[$stackPos - (7 - 5)]), 'elseifs' => $this->semStack[$stackPos - (7 - 6)], 'else' => $this->semStack[$stackPos - (7 - 7)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 156 => function ($stackPos) { + $this->semValue = new Stmt\If_($this->semStack[$stackPos - (10 - 3)], ['stmts' => $this->semStack[$stackPos - (10 - 6)], 'elseifs' => $this->semStack[$stackPos - (10 - 7)], 'else' => $this->semStack[$stackPos - (10 - 8)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); + }, 157 => function ($stackPos) { + $this->semValue = new Stmt\While_($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 158 => function ($stackPos) { + $this->semValue = new Stmt\Do_($this->semStack[$stackPos - (7 - 5)], \is_array($this->semStack[$stackPos - (7 - 2)]) ? $this->semStack[$stackPos - (7 - 2)] : array($this->semStack[$stackPos - (7 - 2)]), $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 159 => function ($stackPos) { + $this->semValue = new Stmt\For_(['init' => $this->semStack[$stackPos - (9 - 3)], 'cond' => $this->semStack[$stackPos - (9 - 5)], 'loop' => $this->semStack[$stackPos - (9 - 7)], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 160 => function ($stackPos) { + $this->semValue = new Stmt\Switch_($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 161 => function ($stackPos) { + $this->semValue = new Stmt\Break_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 162 => function ($stackPos) { + $this->semValue = new Stmt\Continue_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 163 => function ($stackPos) { + $this->semValue = new Stmt\Return_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 164 => function ($stackPos) { + $this->semValue = new Stmt\Global_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 165 => function ($stackPos) { + $this->semValue = new Stmt\Static_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 166 => function ($stackPos) { + $this->semValue = new Stmt\Echo_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 167 => function ($stackPos) { + $this->semValue = new Stmt\InlineHTML($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 168 => function ($stackPos) { + $e = $this->semStack[$stackPos - (2 - 1)]; + if ($e instanceof Expr\Throw_) { + // For backwards-compatibility reasons, convert throw in statement position into + // Stmt\Throw_ rather than Stmt\Expression(Expr\Throw_). + $this->semValue = new Stmt\Throw_($e->expr, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + } else { + $this->semValue = new Stmt\Expression($e, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + } + }, 169 => function ($stackPos) { + $this->semValue = new Stmt\Unset_($this->semStack[$stackPos - (5 - 3)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 170 => function ($stackPos) { + $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 5)][0], ['keyVar' => null, 'byRef' => $this->semStack[$stackPos - (7 - 5)][1], 'stmts' => $this->semStack[$stackPos - (7 - 7)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 171 => function ($stackPos) { + $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (9 - 3)], $this->semStack[$stackPos - (9 - 7)][0], ['keyVar' => $this->semStack[$stackPos - (9 - 5)], 'byRef' => $this->semStack[$stackPos - (9 - 7)][1], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 172 => function ($stackPos) { + $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (6 - 3)], new Expr\Error($this->startAttributeStack[$stackPos - (6 - 4)] + $this->endAttributeStack[$stackPos - (6 - 4)]), ['stmts' => $this->semStack[$stackPos - (6 - 6)]], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 173 => function ($stackPos) { + $this->semValue = new Stmt\Declare_($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 174 => function ($stackPos) { + $this->semValue = new Stmt\TryCatch($this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 5)], $this->semStack[$stackPos - (6 - 6)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + $this->checkTryCatch($this->semValue); + }, 175 => function ($stackPos) { + $this->semValue = new Stmt\Goto_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 176 => function ($stackPos) { + $this->semValue = new Stmt\Label($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 177 => function ($stackPos) { + $this->semValue = array(); + /* means: no statement */ + }, 178 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 179 => function ($stackPos) { + $startAttributes = $this->startAttributeStack[$stackPos - (1 - 1)]; + if (isset($startAttributes['comments'])) { + $this->semValue = new Stmt\Nop($startAttributes + $this->endAttributes); + } else { + $this->semValue = null; + } + if ($this->semValue === null) { + $this->semValue = array(); + } + /* means: no statement */ + }, 180 => function ($stackPos) { + $this->semValue = array(); + }, 181 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 182 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 183 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 184 => function ($stackPos) { + $this->semValue = new Stmt\Catch_($this->semStack[$stackPos - (8 - 3)], $this->semStack[$stackPos - (8 - 4)], $this->semStack[$stackPos - (8 - 7)], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + }, 185 => function ($stackPos) { + $this->semValue = null; + }, 186 => function ($stackPos) { + $this->semValue = new Stmt\Finally_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 187 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 188 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 189 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 190 => function ($stackPos) { + $this->semValue = \false; + }, 191 => function ($stackPos) { + $this->semValue = \true; + }, 192 => function ($stackPos) { + $this->semValue = \false; + }, 193 => function ($stackPos) { + $this->semValue = \true; + }, 194 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 195 => function ($stackPos) { + $this->semValue = []; + }, 196 => function ($stackPos) { + $this->semValue = new Stmt\Function_($this->semStack[$stackPos - (8 - 3)], ['byRef' => $this->semStack[$stackPos - (8 - 2)], 'params' => $this->semStack[$stackPos - (8 - 5)], 'returnType' => $this->semStack[$stackPos - (8 - 7)], 'stmts' => $this->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + }, 197 => function ($stackPos) { + $this->semValue = new Stmt\Function_($this->semStack[$stackPos - (9 - 4)], ['byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 6)], 'returnType' => $this->semStack[$stackPos - (9 - 8)], 'stmts' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => $this->semStack[$stackPos - (9 - 1)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 198 => function ($stackPos) { + $this->semValue = new Stmt\Class_($this->semStack[$stackPos - (8 - 3)], ['type' => $this->semStack[$stackPos - (8 - 2)], 'extends' => $this->semStack[$stackPos - (8 - 4)], 'implements' => $this->semStack[$stackPos - (8 - 5)], 'stmts' => $this->semStack[$stackPos - (8 - 7)], 'attrGroups' => $this->semStack[$stackPos - (8 - 1)]], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + $this->checkClass($this->semValue, $stackPos - (8 - 3)); + }, 199 => function ($stackPos) { + $this->semValue = new Stmt\Interface_($this->semStack[$stackPos - (7 - 3)], ['extends' => $this->semStack[$stackPos - (7 - 4)], 'stmts' => $this->semStack[$stackPos - (7 - 6)], 'attrGroups' => $this->semStack[$stackPos - (7 - 1)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + $this->checkInterface($this->semValue, $stackPos - (7 - 3)); + }, 200 => function ($stackPos) { + $this->semValue = new Stmt\Trait_($this->semStack[$stackPos - (6 - 3)], ['stmts' => $this->semStack[$stackPos - (6 - 5)], 'attrGroups' => $this->semStack[$stackPos - (6 - 1)]], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 201 => function ($stackPos) { + $this->semValue = 0; + }, 202 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_ABSTRACT; + }, 203 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_FINAL; + }, 204 => function ($stackPos) { + $this->semValue = null; + }, 205 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 206 => function ($stackPos) { + $this->semValue = array(); + }, 207 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 208 => function ($stackPos) { + $this->semValue = array(); + }, 209 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 210 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 211 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 212 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 213 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 214 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 215 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 216 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 217 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 218 => function ($stackPos) { + $this->semValue = null; + }, 219 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 220 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 221 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 222 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 223 => function ($stackPos) { + $this->semValue = new Stmt\DeclareDeclare($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 224 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 225 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 3)]; + }, 226 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 227 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (5 - 3)]; + }, 228 => function ($stackPos) { + $this->semValue = array(); + }, 229 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 230 => function ($stackPos) { + $this->semValue = new Stmt\Case_($this->semStack[$stackPos - (4 - 2)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 231 => function ($stackPos) { + $this->semValue = new Stmt\Case_(null, $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 232 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 233 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 234 => function ($stackPos) { + $this->semValue = new Expr\Match_($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 6)], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 235 => function ($stackPos) { + $this->semValue = []; + }, 236 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 237 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 238 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 239 => function ($stackPos) { + $this->semValue = new Node\MatchArm($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 240 => function ($stackPos) { + $this->semValue = new Node\MatchArm(null, $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 241 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 242 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 243 => function ($stackPos) { + $this->semValue = array(); + }, 244 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 245 => function ($stackPos) { + $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos - (5 - 3)], \is_array($this->semStack[$stackPos - (5 - 5)]) ? $this->semStack[$stackPos - (5 - 5)] : array($this->semStack[$stackPos - (5 - 5)]), $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 246 => function ($stackPos) { + $this->semValue = array(); + }, 247 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 248 => function ($stackPos) { + $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 6)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 249 => function ($stackPos) { + $this->semValue = null; + }, 250 => function ($stackPos) { + $this->semValue = new Stmt\Else_(\is_array($this->semStack[$stackPos - (2 - 2)]) ? $this->semStack[$stackPos - (2 - 2)] : array($this->semStack[$stackPos - (2 - 2)]), $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 251 => function ($stackPos) { + $this->semValue = null; + }, 252 => function ($stackPos) { + $this->semValue = new Stmt\Else_($this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 253 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); + }, 254 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (2 - 2)], \true); + }, 255 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); + }, 256 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); + }, 257 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 258 => function ($stackPos) { + $this->semValue = array(); + }, 259 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 260 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 261 => function ($stackPos) { + $this->semValue = 0; + }, 262 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PUBLIC; + }, 263 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PROTECTED; + }, 264 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PRIVATE; + }, 265 => function ($stackPos) { + $this->semValue = new Node\Param($this->semStack[$stackPos - (6 - 6)], null, $this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 4)], $this->semStack[$stackPos - (6 - 5)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 1)]); + $this->checkParam($this->semValue); + }, 266 => function ($stackPos) { + $this->semValue = new Node\Param($this->semStack[$stackPos - (8 - 6)], $this->semStack[$stackPos - (8 - 8)], $this->semStack[$stackPos - (8 - 3)], $this->semStack[$stackPos - (8 - 4)], $this->semStack[$stackPos - (8 - 5)], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (8 - 2)], $this->semStack[$stackPos - (8 - 1)]); + $this->checkParam($this->semValue); + }, 267 => function ($stackPos) { + $this->semValue = new Node\Param(new Expr\Error($this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes), null, $this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 4)], $this->semStack[$stackPos - (6 - 5)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 1)]); + }, 268 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 269 => function ($stackPos) { + $this->semValue = new Node\NullableType($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 270 => function ($stackPos) { + $this->semValue = new Node\UnionType($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 271 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 272 => function ($stackPos) { + $this->semValue = new Node\Name('static', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 273 => function ($stackPos) { + $this->semValue = $this->handleBuiltinTypes($this->semStack[$stackPos - (1 - 1)]); + }, 274 => function ($stackPos) { + $this->semValue = new Node\Identifier('array', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 275 => function ($stackPos) { + $this->semValue = new Node\Identifier('callable', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 276 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); + }, 277 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 278 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); + }, 279 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 280 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 281 => function ($stackPos) { + $this->semValue = new Node\NullableType($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 282 => function ($stackPos) { + $this->semValue = new Node\UnionType($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 283 => function ($stackPos) { + $this->semValue = null; + }, 284 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 285 => function ($stackPos) { + $this->semValue = null; + }, 286 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 287 => function ($stackPos) { + $this->semValue = null; + }, 288 => function ($stackPos) { + $this->semValue = array(); + }, 289 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 290 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 291 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 292 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (1 - 1)], \false, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 293 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (2 - 2)], \true, \false, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 294 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (2 - 2)], \false, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 295 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (3 - 3)], \false, \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (3 - 1)]); + }, 296 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 297 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 298 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 299 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 300 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 301 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 302 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 303 => function ($stackPos) { + $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos - (1 - 1)], null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 304 => function ($stackPos) { + $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 305 => function ($stackPos) { + if ($this->semStack[$stackPos - (2 - 2)] !== null) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } + }, 306 => function ($stackPos) { + $this->semValue = array(); + }, 307 => function ($stackPos) { + $startAttributes = $this->lookaheadStartAttributes; + if (isset($startAttributes['comments'])) { + $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); + } else { + $nop = null; + } + if ($nop !== null) { + $this->semStack[$stackPos - (1 - 1)][] = $nop; + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 308 => function ($stackPos) { + $this->semValue = new Stmt\Property($this->semStack[$stackPos - (5 - 2)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 1)]); + $this->checkProperty($this->semValue, $stackPos - (5 - 2)); + }, 309 => function ($stackPos) { + $this->semValue = new Stmt\ClassConst($this->semStack[$stackPos - (5 - 4)], $this->semStack[$stackPos - (5 - 2)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (5 - 1)]); + $this->checkClassConst($this->semValue, $stackPos - (5 - 2)); + }, 310 => function ($stackPos) { + $this->semValue = new Stmt\ClassMethod($this->semStack[$stackPos - (10 - 5)], ['type' => $this->semStack[$stackPos - (10 - 2)], 'byRef' => $this->semStack[$stackPos - (10 - 4)], 'params' => $this->semStack[$stackPos - (10 - 7)], 'returnType' => $this->semStack[$stackPos - (10 - 9)], 'stmts' => $this->semStack[$stackPos - (10 - 10)], 'attrGroups' => $this->semStack[$stackPos - (10 - 1)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); + $this->checkClassMethod($this->semValue, $stackPos - (10 - 2)); + }, 311 => function ($stackPos) { + $this->semValue = new Stmt\TraitUse($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 312 => function ($stackPos) { + $this->semValue = null; + /* will be skipped */ + }, 313 => function ($stackPos) { + $this->semValue = array(); + }, 314 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 315 => function ($stackPos) { + $this->semValue = array(); + }, 316 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 317 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Precedence($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 318 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (5 - 1)][0], $this->semStack[$stackPos - (5 - 1)][1], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 319 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], $this->semStack[$stackPos - (4 - 3)], null, $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 320 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 321 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 322 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); + }, 323 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 324 => function ($stackPos) { + $this->semValue = array(null, $this->semStack[$stackPos - (1 - 1)]); + }, 325 => function ($stackPos) { + $this->semValue = null; + }, 326 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 327 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 328 => function ($stackPos) { + $this->semValue = 0; + }, 329 => function ($stackPos) { + $this->semValue = 0; + }, 330 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 331 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 332 => function ($stackPos) { + $this->checkModifier($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $this->semValue = $this->semStack[$stackPos - (2 - 1)] | $this->semStack[$stackPos - (2 - 2)]; + }, 333 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PUBLIC; + }, 334 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PROTECTED; + }, 335 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PRIVATE; + }, 336 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_STATIC; + }, 337 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_ABSTRACT; + }, 338 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_FINAL; + }, 339 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 340 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 341 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 342 => function ($stackPos) { + $this->semValue = new Node\VarLikeIdentifier(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 343 => function ($stackPos) { + $this->semValue = new Stmt\PropertyProperty($this->semStack[$stackPos - (1 - 1)], null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 344 => function ($stackPos) { + $this->semValue = new Stmt\PropertyProperty($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 345 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 346 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 347 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 348 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 349 => function ($stackPos) { + $this->semValue = array(); + }, 350 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 351 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 352 => function ($stackPos) { + $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 353 => function ($stackPos) { + $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 354 => function ($stackPos) { + $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 355 => function ($stackPos) { + $this->semValue = new Expr\AssignRef($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 356 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 357 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 358 => function ($stackPos) { + $this->semValue = new Expr\Clone_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 359 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 360 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 361 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 362 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 363 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 364 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 365 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 366 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 367 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 368 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 369 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 370 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 371 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Coalesce($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 372 => function ($stackPos) { + $this->semValue = new Expr\PostInc($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 373 => function ($stackPos) { + $this->semValue = new Expr\PreInc($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 374 => function ($stackPos) { + $this->semValue = new Expr\PostDec($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 375 => function ($stackPos) { + $this->semValue = new Expr\PreDec($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 376 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BooleanOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 377 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BooleanAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 378 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 379 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 380 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 381 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 382 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 383 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 384 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 385 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 386 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 387 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 388 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 389 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 390 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 391 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 392 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 393 => function ($stackPos) { + $this->semValue = new Expr\UnaryPlus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 394 => function ($stackPos) { + $this->semValue = new Expr\UnaryMinus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 395 => function ($stackPos) { + $this->semValue = new Expr\BooleanNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 396 => function ($stackPos) { + $this->semValue = new Expr\BitwiseNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 397 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Identical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 398 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\NotIdentical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 399 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Equal($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 400 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\NotEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 401 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Spaceship($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 402 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Smaller($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 403 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\SmallerOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 404 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Greater($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 405 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\GreaterOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 406 => function ($stackPos) { + $this->semValue = new Expr\Instanceof_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 407 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 408 => function ($stackPos) { + $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (5 - 1)], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 409 => function ($stackPos) { + $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (4 - 1)], null, $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 410 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Coalesce($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 411 => function ($stackPos) { + $this->semValue = new Expr\Isset_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 412 => function ($stackPos) { + $this->semValue = new Expr\Empty_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 413 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 414 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE_ONCE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 415 => function ($stackPos) { + $this->semValue = new Expr\Eval_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 416 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 417 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE_ONCE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 418 => function ($stackPos) { + $this->semValue = new Expr\Cast\Int_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 419 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes; + $attrs['kind'] = $this->getFloatCastKind($this->semStack[$stackPos - (2 - 1)]); + $this->semValue = new Expr\Cast\Double($this->semStack[$stackPos - (2 - 2)], $attrs); + }, 420 => function ($stackPos) { + $this->semValue = new Expr\Cast\String_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 421 => function ($stackPos) { + $this->semValue = new Expr\Cast\Array_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 422 => function ($stackPos) { + $this->semValue = new Expr\Cast\Object_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 423 => function ($stackPos) { + $this->semValue = new Expr\Cast\Bool_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 424 => function ($stackPos) { + $this->semValue = new Expr\Cast\Unset_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 425 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes; + $attrs['kind'] = \strtolower($this->semStack[$stackPos - (2 - 1)]) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE; + $this->semValue = new Expr\Exit_($this->semStack[$stackPos - (2 - 2)], $attrs); + }, 426 => function ($stackPos) { + $this->semValue = new Expr\ErrorSuppress($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 427 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 428 => function ($stackPos) { + $this->semValue = new Expr\ShellExec($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 429 => function ($stackPos) { + $this->semValue = new Expr\Print_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 430 => function ($stackPos) { + $this->semValue = new Expr\Yield_(null, null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 431 => function ($stackPos) { + $this->semValue = new Expr\Yield_($this->semStack[$stackPos - (2 - 2)], null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 432 => function ($stackPos) { + $this->semValue = new Expr\Yield_($this->semStack[$stackPos - (4 - 4)], $this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 433 => function ($stackPos) { + $this->semValue = new Expr\YieldFrom($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 434 => function ($stackPos) { + $this->semValue = new Expr\Throw_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 435 => function ($stackPos) { + $this->semValue = new Expr\ArrowFunction(['static' => \false, 'byRef' => $this->semStack[$stackPos - (8 - 2)], 'params' => $this->semStack[$stackPos - (8 - 4)], 'returnType' => $this->semStack[$stackPos - (8 - 6)], 'expr' => $this->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + }, 436 => function ($stackPos) { + $this->semValue = new Expr\ArrowFunction(['static' => \true, 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 5)], 'returnType' => $this->semStack[$stackPos - (9 - 7)], 'expr' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 437 => function ($stackPos) { + $this->semValue = new Expr\Closure(['static' => \false, 'byRef' => $this->semStack[$stackPos - (8 - 2)], 'params' => $this->semStack[$stackPos - (8 - 4)], 'uses' => $this->semStack[$stackPos - (8 - 6)], 'returnType' => $this->semStack[$stackPos - (8 - 7)], 'stmts' => $this->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + }, 438 => function ($stackPos) { + $this->semValue = new Expr\Closure(['static' => \true, 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 5)], 'uses' => $this->semStack[$stackPos - (9 - 7)], 'returnType' => $this->semStack[$stackPos - (9 - 8)], 'stmts' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 439 => function ($stackPos) { + $this->semValue = new Expr\ArrowFunction(['static' => \false, 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 5)], 'returnType' => $this->semStack[$stackPos - (9 - 7)], 'expr' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => $this->semStack[$stackPos - (9 - 1)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 440 => function ($stackPos) { + $this->semValue = new Expr\ArrowFunction(['static' => \true, 'byRef' => $this->semStack[$stackPos - (10 - 4)], 'params' => $this->semStack[$stackPos - (10 - 6)], 'returnType' => $this->semStack[$stackPos - (10 - 8)], 'expr' => $this->semStack[$stackPos - (10 - 10)], 'attrGroups' => $this->semStack[$stackPos - (10 - 1)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); + }, 441 => function ($stackPos) { + $this->semValue = new Expr\Closure(['static' => \false, 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 5)], 'uses' => $this->semStack[$stackPos - (9 - 7)], 'returnType' => $this->semStack[$stackPos - (9 - 8)], 'stmts' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => $this->semStack[$stackPos - (9 - 1)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 442 => function ($stackPos) { + $this->semValue = new Expr\Closure(['static' => \true, 'byRef' => $this->semStack[$stackPos - (10 - 4)], 'params' => $this->semStack[$stackPos - (10 - 6)], 'uses' => $this->semStack[$stackPos - (10 - 8)], 'returnType' => $this->semStack[$stackPos - (10 - 9)], 'stmts' => $this->semStack[$stackPos - (10 - 10)], 'attrGroups' => $this->semStack[$stackPos - (10 - 1)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); + }, 443 => function ($stackPos) { + $this->semValue = array(new Stmt\Class_(null, ['type' => 0, 'extends' => $this->semStack[$stackPos - (8 - 4)], 'implements' => $this->semStack[$stackPos - (8 - 5)], 'stmts' => $this->semStack[$stackPos - (8 - 7)], 'attrGroups' => $this->semStack[$stackPos - (8 - 1)]], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes), $this->semStack[$stackPos - (8 - 3)]); + $this->checkClass($this->semValue[0], -1); + }, 444 => function ($stackPos) { + $this->semValue = new Expr\New_($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 445 => function ($stackPos) { + list($class, $ctorArgs) = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = new Expr\New_($class, $ctorArgs, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 446 => function ($stackPos) { + $this->semValue = array(); + }, 447 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 3)]; + }, 448 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 449 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 450 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 451 => function ($stackPos) { + $this->semValue = new Expr\ClosureUse($this->semStack[$stackPos - (2 - 2)], $this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 452 => function ($stackPos) { + $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 453 => function ($stackPos) { + $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 454 => function ($stackPos) { + $this->semValue = new Expr\StaticCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 455 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 456 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 457 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 458 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 459 => function ($stackPos) { + $this->semValue = new Name\FullyQualified(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 460 => function ($stackPos) { + $this->semValue = new Name\Relative(\substr($this->semStack[$stackPos - (1 - 1)], 10), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 461 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 462 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 463 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 464 => function ($stackPos) { + $this->semValue = new Expr\Error($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->errorState = 2; + }, 465 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 466 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 467 => function ($stackPos) { + $this->semValue = null; + }, 468 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 469 => function ($stackPos) { + $this->semValue = array(); + }, 470 => function ($stackPos) { + $this->semValue = array(new Scalar\EncapsedStringPart(Scalar\String_::parseEscapeSequences($this->semStack[$stackPos - (1 - 1)], '`'), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes)); + }, 471 => function ($stackPos) { + foreach ($this->semStack[$stackPos - (1 - 1)] as $s) { + if ($s instanceof Node\Scalar\EncapsedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', \true); + } + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 472 => function ($stackPos) { + $this->semValue = array(); + }, 473 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 474 => function ($stackPos) { + $this->semValue = new Expr\ConstFetch($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 475 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Line($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 476 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\File($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 477 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Dir($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 478 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Class_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 479 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Trait_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 480 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Method($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 481 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Function_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 482 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Namespace_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 483 => function ($stackPos) { + $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 484 => function ($stackPos) { + $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (3 - 1)], new Expr\Error($this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)]), $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->errorState = 2; + }, 485 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes; + $attrs['kind'] = Expr\Array_::KIND_SHORT; + $this->semValue = new Expr\Array_($this->semStack[$stackPos - (3 - 2)], $attrs); + }, 486 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes; + $attrs['kind'] = Expr\Array_::KIND_LONG; + $this->semValue = new Expr\Array_($this->semStack[$stackPos - (4 - 3)], $attrs); + }, 487 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 488 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes; + $attrs['kind'] = $this->semStack[$stackPos - (1 - 1)][0] === "'" || $this->semStack[$stackPos - (1 - 1)][1] === "'" && ($this->semStack[$stackPos - (1 - 1)][0] === 'b' || $this->semStack[$stackPos - (1 - 1)][0] === 'B') ? Scalar\String_::KIND_SINGLE_QUOTED : Scalar\String_::KIND_DOUBLE_QUOTED; + $this->semValue = new Scalar\String_(Scalar\String_::parse($this->semStack[$stackPos - (1 - 1)]), $attrs); + }, 489 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes; + $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED; + foreach ($this->semStack[$stackPos - (3 - 2)] as $s) { + if ($s instanceof Node\Scalar\EncapsedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '"', \true); + } + } + $this->semValue = new Scalar\Encapsed($this->semStack[$stackPos - (3 - 2)], $attrs); + }, 490 => function ($stackPos) { + $this->semValue = $this->parseLNumber($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 491 => function ($stackPos) { + $this->semValue = new Scalar\DNumber(Scalar\DNumber::parse($this->semStack[$stackPos - (1 - 1)]), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 492 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 493 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 494 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 495 => function ($stackPos) { + $this->semValue = $this->parseDocString($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)], \true); + }, 496 => function ($stackPos) { + $this->semValue = $this->parseDocString($this->semStack[$stackPos - (2 - 1)], '', $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (2 - 2)] + $this->endAttributeStack[$stackPos - (2 - 2)], \true); + }, 497 => function ($stackPos) { + $this->semValue = $this->parseDocString($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)], \true); + }, 498 => function ($stackPos) { + $this->semValue = null; + }, 499 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 500 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 501 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 502 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 503 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 504 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 505 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 506 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 507 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 508 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 509 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 510 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 511 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 512 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 513 => function ($stackPos) { + $this->semValue = new Expr\MethodCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 514 => function ($stackPos) { + $this->semValue = new Expr\NullsafeMethodCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 515 => function ($stackPos) { + $this->semValue = null; + }, 516 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 517 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 518 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 519 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 520 => function ($stackPos) { + $this->semValue = new Expr\NullsafePropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 521 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 522 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 523 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 524 => function ($stackPos) { + $this->semValue = new Expr\Variable(new Expr\Error($this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes), $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + $this->errorState = 2; + }, 525 => function ($stackPos) { + $var = $this->semStack[$stackPos - (1 - 1)]->name; + $this->semValue = \is_string($var) ? new Node\VarLikeIdentifier($var, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes) : $var; + }, 526 => function ($stackPos) { + $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 527 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 528 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 529 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 530 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 531 => function ($stackPos) { + $this->semValue = new Expr\NullsafePropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 532 => function ($stackPos) { + $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 533 => function ($stackPos) { + $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 534 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 535 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 536 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 537 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 538 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 539 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 540 => function ($stackPos) { + $this->semValue = new Expr\Error($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->errorState = 2; + }, 541 => function ($stackPos) { + $this->semValue = new Expr\List_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 542 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + $end = \count($this->semValue) - 1; + if ($this->semValue[$end] === null) { + \array_pop($this->semValue); + } + }, 543 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 544 => function ($stackPos) { + /* do nothing -- prevent default action of $$=$this->semStack[$1]. See $551. */ + }, 545 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 546 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 547 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 548 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (2 - 2)], null, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 549 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 550 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (3 - 3)], $this->semStack[$stackPos - (3 - 1)], \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 551 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (4 - 4)], $this->semStack[$stackPos - (4 - 1)], \true, $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 552 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (3 - 3)], $this->semStack[$stackPos - (3 - 1)], \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 553 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (2 - 2)], null, \false, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 554 => function ($stackPos) { + $this->semValue = null; + }, 555 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 556 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 557 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 558 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); + }, 559 => function ($stackPos) { + $this->semValue = new Scalar\EncapsedStringPart($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 560 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 561 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 562 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 563 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 564 => function ($stackPos) { + $this->semValue = new Expr\NullsafePropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 565 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 566 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 567 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 4)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 568 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 569 => function ($stackPos) { + $this->semValue = new Scalar\String_($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 570 => function ($stackPos) { + $this->semValue = $this->parseNumString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 571 => function ($stackPos) { + $this->semValue = $this->parseNumString('-' . $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 572 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }]; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/Parser/Tokens.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/Parser/Tokens.php new file mode 100644 index 000000000..a22fe3da8 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/Parser/Tokens.php @@ -0,0 +1,144 @@ +lexer = $lexer; + if (isset($options['throwOnError'])) { + throw new \LogicException('"throwOnError" is no longer supported, use "errorHandler" instead'); + } + $this->initReduceCallbacks(); + } + /** + * Parses PHP code into a node tree. + * + * If a non-throwing error handler is used, the parser will continue parsing after an error + * occurred and attempt to build a partial AST. + * + * @param string $code The source code to parse + * @param ErrorHandler|null $errorHandler Error handler to use for lexer/parser errors, defaults + * to ErrorHandler\Throwing. + * + * @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and + * the parser was unable to recover from an error). + */ + public function parse($code, ErrorHandler $errorHandler = null) + { + if (!\is_string($code)) { + if (!(\is_string($code) || \is_object($code) && \method_exists($code, '__toString') || (\is_bool($code) || \is_numeric($code)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($code) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (string) $code; + } + } + $this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing(); + $this->lexer->startLexing($code, $this->errorHandler); + $result = $this->doParse(); + // Clear out some of the interior state, so we don't hold onto unnecessary + // memory between uses of the parser + $this->startAttributeStack = []; + $this->endAttributeStack = []; + $this->semStack = []; + $this->semValue = null; + return $result; + } + protected function doParse() + { + // We start off with no lookahead-token + $symbol = self::SYMBOL_NONE; + // The attributes for a node are taken from the first and last token of the node. + // From the first token only the startAttributes are taken and from the last only + // the endAttributes. Both are merged using the array union operator (+). + $startAttributes = []; + $endAttributes = []; + $this->endAttributes = $endAttributes; + // Keep stack of start and end attributes + $this->startAttributeStack = []; + $this->endAttributeStack = [$endAttributes]; + // Start off in the initial state and keep a stack of previous states + $state = 0; + $stateStack = [$state]; + // Semantic value stack (contains values of tokens and semantic action results) + $this->semStack = []; + // Current position in the stack(s) + $stackPos = 0; + $this->errorState = 0; + for (;;) { + //$this->traceNewState($state, $symbol); + if ($this->actionBase[$state] === 0) { + $rule = $this->actionDefault[$state]; + } else { + if ($symbol === self::SYMBOL_NONE) { + // Fetch the next token id from the lexer and fetch additional info by-ref. + // The end attributes are fetched into a temporary variable and only set once the token is really + // shifted (not during read). Otherwise you would sometimes get off-by-one errors, when a rule is + // reduced after a token was read but not yet shifted. + $tokenId = $this->lexer->getNextToken($tokenValue, $startAttributes, $endAttributes); + // map the lexer token id to the internally used symbols + $symbol = $tokenId >= 0 && $tokenId < $this->tokenToSymbolMapSize ? $this->tokenToSymbol[$tokenId] : $this->invalidSymbol; + if ($symbol === $this->invalidSymbol) { + throw new \RangeException(\sprintf('The lexer returned an invalid token (id=%d, value=%s)', $tokenId, $tokenValue)); + } + // Allow productions to access the start attributes of the lookahead token. + $this->lookaheadStartAttributes = $startAttributes; + //$this->traceRead($symbol); + } + $idx = $this->actionBase[$state] + $symbol; + if (($idx >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol || $state < $this->YY2TBLSTATE && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $symbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol) && ($action = $this->action[$idx]) !== $this->defaultAction) { + /* + * >= numNonLeafStates: shift and reduce + * > 0: shift + * = 0: accept + * < 0: reduce + * = -YYUNEXPECTED: error + */ + if ($action > 0) { + /* shift */ + //$this->traceShift($symbol); + ++$stackPos; + $stateStack[$stackPos] = $state = $action; + $this->semStack[$stackPos] = $tokenValue; + $this->startAttributeStack[$stackPos] = $startAttributes; + $this->endAttributeStack[$stackPos] = $endAttributes; + $this->endAttributes = $endAttributes; + $symbol = self::SYMBOL_NONE; + if ($this->errorState) { + --$this->errorState; + } + if ($action < $this->numNonLeafStates) { + continue; + } + /* $yyn >= numNonLeafStates means shift-and-reduce */ + $rule = $action - $this->numNonLeafStates; + } else { + $rule = -$action; + } + } else { + $rule = $this->actionDefault[$state]; + } + } + for (;;) { + if ($rule === 0) { + /* accept */ + //$this->traceAccept(); + return $this->semValue; + } elseif ($rule !== $this->unexpectedTokenRule) { + /* reduce */ + //$this->traceReduce($rule); + try { + $this->reduceCallbacks[$rule]($stackPos); + } catch (Error $e) { + if (-1 === $e->getStartLine() && isset($startAttributes['startLine'])) { + $e->setStartLine($startAttributes['startLine']); + } + $this->emitError($e); + // Can't recover from this type of error + return null; + } + /* Goto - shift nonterminal */ + $lastEndAttributes = $this->endAttributeStack[$stackPos]; + $ruleLength = $this->ruleToLength[$rule]; + $stackPos -= $ruleLength; + $nonTerminal = $this->ruleToNonTerminal[$rule]; + $idx = $this->gotoBase[$nonTerminal] + $stateStack[$stackPos]; + if ($idx >= 0 && $idx < $this->gotoTableSize && $this->gotoCheck[$idx] === $nonTerminal) { + $state = $this->goto[$idx]; + } else { + $state = $this->gotoDefault[$nonTerminal]; + } + ++$stackPos; + $stateStack[$stackPos] = $state; + $this->semStack[$stackPos] = $this->semValue; + $this->endAttributeStack[$stackPos] = $lastEndAttributes; + if ($ruleLength === 0) { + // Empty productions use the start attributes of the lookahead token. + $this->startAttributeStack[$stackPos] = $this->lookaheadStartAttributes; + } + } else { + /* error */ + switch ($this->errorState) { + case 0: + $msg = $this->getErrorMessage($symbol, $state); + $this->emitError(new Error($msg, $startAttributes + $endAttributes)); + // Break missing intentionally + case 1: + case 2: + $this->errorState = 3; + // Pop until error-expecting state uncovered + while (!(($idx = $this->actionBase[$state] + $this->errorSymbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $this->errorSymbol || $state < $this->YY2TBLSTATE && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $this->errorSymbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $this->errorSymbol) || ($action = $this->action[$idx]) === $this->defaultAction) { + // Not totally sure about this + if ($stackPos <= 0) { + // Could not recover from error + return null; + } + $state = $stateStack[--$stackPos]; + //$this->tracePop($state); + } + //$this->traceShift($this->errorSymbol); + ++$stackPos; + $stateStack[$stackPos] = $state = $action; + // We treat the error symbol as being empty, so we reset the end attributes + // to the end attributes of the last non-error symbol + $this->startAttributeStack[$stackPos] = $this->lookaheadStartAttributes; + $this->endAttributeStack[$stackPos] = $this->endAttributeStack[$stackPos - 1]; + $this->endAttributes = $this->endAttributeStack[$stackPos - 1]; + break; + case 3: + if ($symbol === 0) { + // Reached EOF without recovering from error + return null; + } + //$this->traceDiscard($symbol); + $symbol = self::SYMBOL_NONE; + break 2; + } + } + if ($state < $this->numNonLeafStates) { + break; + } + /* >= numNonLeafStates means shift-and-reduce */ + $rule = $state - $this->numNonLeafStates; + } + } + throw new \RuntimeException('Reached end of parser loop'); + } + protected function emitError(Error $error) + { + $this->errorHandler->handleError($error); + } + /** + * Format error message including expected tokens. + * + * @param int $symbol Unexpected symbol + * @param int $state State at time of error + * + * @return string Formatted error message + */ + protected function getErrorMessage($symbol, $state) + { + if (!\is_int($symbol)) { + if (!(\is_bool($symbol) || \is_numeric($symbol))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($symbol) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($symbol) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $symbol = (int) $symbol; + } + } + if (!\is_int($state)) { + if (!(\is_bool($state) || \is_numeric($state))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($state) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($state) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $state = (int) $state; + } + } + $expectedString = ''; + if ($expected = $this->getExpectedTokens($state)) { + $expectedString = ', expecting ' . \implode(' or ', $expected); + } + $phabelReturn = 'Syntax error, unexpected ' . $this->symbolToName[$symbol] . $expectedString; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Get limited number of expected tokens in given state. + * + * @param int $state State + * + * @return string[] Expected tokens. If too many, an empty array is returned. + */ + protected function getExpectedTokens($state) + { + if (!\is_int($state)) { + if (!(\is_bool($state) || \is_numeric($state))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($state) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($state) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $state = (int) $state; + } + } + $expected = []; + $base = $this->actionBase[$state]; + foreach ($this->symbolToName as $symbol => $name) { + $idx = $base + $symbol; + if ($idx >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol || $state < $this->YY2TBLSTATE && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $symbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol) { + if ($this->action[$idx] !== $this->unexpectedTokenRule && $this->action[$idx] !== $this->defaultAction && $symbol !== $this->errorSymbol) { + if (\count($expected) === 4) { + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /* Too many expected tokens */ + return $phabelReturn; + } + $expected[] = $name; + } + } + } + $phabelReturn = $expected; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /* + * Tracing functions used for debugging the parser. + */ + /* + protected function traceNewState($state, $symbol) { + echo '% State ' . $state + . ', Lookahead ' . ($symbol == self::SYMBOL_NONE ? '--none--' : $this->symbolToName[$symbol]) . "\n"; + } + + protected function traceRead($symbol) { + echo '% Reading ' . $this->symbolToName[$symbol] . "\n"; + } + + protected function traceShift($symbol) { + echo '% Shift ' . $this->symbolToName[$symbol] . "\n"; + } + + protected function traceAccept() { + echo "% Accepted.\n"; + } + + protected function traceReduce($n) { + echo '% Reduce by (' . $n . ') ' . $this->productions[$n] . "\n"; + } + + protected function tracePop($state) { + echo '% Recovering, uncovered state ' . $state . "\n"; + } + + protected function traceDiscard($symbol) { + echo '% Discard ' . $this->symbolToName[$symbol] . "\n"; + } + */ + /* + * Helper functions invoked by semantic actions + */ + /** + * Moves statements of semicolon-style namespaces into $ns->stmts and checks various error conditions. + * + * @param Node\Stmt[] $stmts + * @return Node\Stmt[] + */ + protected function handleNamespaces(array $stmts) + { + $hasErrored = \false; + $style = $this->getNamespacingStyle($stmts); + if (null === $style) { + $phabelReturn = $stmts; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // not namespaced, nothing to do + return $phabelReturn; + } elseif ('brace' === $style) { + // For braced namespaces we only have to check that there are no invalid statements between the namespaces + $afterFirstNamespace = \false; + foreach ($stmts as $stmt) { + if ($stmt instanceof Node\Stmt\Namespace_) { + $afterFirstNamespace = \true; + } elseif (!$stmt instanceof Node\Stmt\HaltCompiler && !$stmt instanceof Node\Stmt\Nop && $afterFirstNamespace && !$hasErrored) { + $this->emitError(new Error('No code may exist outside of namespace {}', $stmt->getAttributes())); + $hasErrored = \true; + // Avoid one error for every statement + } + } + $phabelReturn = $stmts; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } else { + // For semicolon namespaces we have to move the statements after a namespace declaration into ->stmts + $resultStmts = []; + $targetStmts =& $resultStmts; + $lastNs = null; + foreach ($stmts as $stmt) { + if ($stmt instanceof Node\Stmt\Namespace_) { + if ($lastNs !== null) { + $this->fixupNamespaceAttributes($lastNs); + } + if ($stmt->stmts === null) { + $stmt->stmts = []; + $targetStmts =& $stmt->stmts; + $resultStmts[] = $stmt; + } else { + // This handles the invalid case of mixed style namespaces + $resultStmts[] = $stmt; + $targetStmts =& $resultStmts; + } + $lastNs = $stmt; + } elseif ($stmt instanceof Node\Stmt\HaltCompiler) { + // __halt_compiler() is not moved into the namespace + $resultStmts[] = $stmt; + } else { + $targetStmts[] = $stmt; + } + } + if ($lastNs !== null) { + $this->fixupNamespaceAttributes($lastNs); + } + $phabelReturn = $resultStmts; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + private function fixupNamespaceAttributes(Node\Stmt\Namespace_ $stmt) + { + // We moved the statements into the namespace node, as such the end of the namespace node + // needs to be extended to the end of the statements. + if (empty($stmt->stmts)) { + return; + } + // We only move the builtin end attributes here. This is the best we can do with the + // knowledge we have. + $endAttributes = ['endLine', 'endFilePos', 'endTokenPos']; + $lastStmt = $stmt->stmts[\count($stmt->stmts) - 1]; + foreach ($endAttributes as $endAttribute) { + if ($lastStmt->hasAttribute($endAttribute)) { + $stmt->setAttribute($endAttribute, $lastStmt->getAttribute($endAttribute)); + } + } + } + /** + * Determine namespacing style (semicolon or brace) + * + * @param Node[] $stmts Top-level statements. + * + * @return null|string One of "semicolon", "brace" or null (no namespaces) + */ + private function getNamespacingStyle(array $stmts) + { + $style = null; + $hasNotAllowedStmts = \false; + foreach ($stmts as $i => $stmt) { + if ($stmt instanceof Node\Stmt\Namespace_) { + $currentStyle = null === $stmt->stmts ? 'semicolon' : 'brace'; + if (null === $style) { + $style = $currentStyle; + if ($hasNotAllowedStmts) { + $this->emitError(new Error('Namespace declaration statement has to be the very first statement in the script', $stmt->getLine())); + } + } elseif ($style !== $currentStyle) { + $this->emitError(new Error('Cannot mix bracketed namespace declarations with unbracketed namespace declarations', $stmt->getLine())); + // Treat like semicolon style for namespace normalization + return 'semicolon'; + } + continue; + } + /* declare(), __halt_compiler() and nops can be used before a namespace declaration */ + if ($stmt instanceof Node\Stmt\Declare_ || $stmt instanceof Node\Stmt\HaltCompiler || $stmt instanceof Node\Stmt\Nop) { + continue; + } + /* There may be a hashbang line at the very start of the file */ + if ($i === 0 && $stmt instanceof Node\Stmt\InlineHTML && \preg_match('/\\A#!.*\\r?\\n\\z/', $stmt->value)) { + continue; + } + /* Everything else if forbidden before namespace declarations */ + $hasNotAllowedStmts = \true; + } + return $style; + } + /** + * Fix up parsing of static property calls in PHP 5. + * + * In PHP 5 A::$b[c][d] and A::$b[c][d]() have very different interpretation. The former is + * interpreted as (A::$b)[c][d], while the latter is the same as A::{$b[c][d]}(). We parse the + * latter as the former initially and this method fixes the AST into the correct form when we + * encounter the "()". + * + * @param Node\Expr\StaticPropertyFetch|Node\Expr\ArrayDimFetch $prop + * @param Node\Arg[] $args + * @param array $attributes + * + * @return Expr\StaticCall + */ + protected function fixupPhp5StaticPropCall($prop, array $args, array $attributes) + { + if ($prop instanceof Node\Expr\StaticPropertyFetch) { + $name = $prop->name instanceof VarLikeIdentifier ? $prop->name->toString() : $prop->name; + $var = new Expr\Variable($name, $prop->name->getAttributes()); + $phabelReturn = new Expr\StaticCall($prop->class, $var, $args, $attributes); + if (!$phabelReturn instanceof Expr\StaticCall) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr\\StaticCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } elseif ($prop instanceof Node\Expr\ArrayDimFetch) { + $tmp = $prop; + while ($tmp->var instanceof Node\Expr\ArrayDimFetch) { + $tmp = $tmp->var; + } + /** @var Expr\StaticPropertyFetch $staticProp */ + $staticProp = $tmp->var; + // Set start attributes to attributes of innermost node + $tmp = $prop; + $this->fixupStartAttributes($tmp, $staticProp->name); + while ($tmp->var instanceof Node\Expr\ArrayDimFetch) { + $tmp = $tmp->var; + $this->fixupStartAttributes($tmp, $staticProp->name); + } + $name = $staticProp->name instanceof VarLikeIdentifier ? $staticProp->name->toString() : $staticProp->name; + $tmp->var = new Expr\Variable($name, $staticProp->name->getAttributes()); + $phabelReturn = new Expr\StaticCall($staticProp->class, $prop, $args, $attributes); + if (!$phabelReturn instanceof Expr\StaticCall) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr\\StaticCall, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } else { + throw new \Exception(); + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type Expr\\StaticCall, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + protected function fixupStartAttributes(Node $to, Node $from) + { + $startAttributes = ['startLine', 'startFilePos', 'startTokenPos']; + foreach ($startAttributes as $startAttribute) { + if ($from->hasAttribute($startAttribute)) { + $to->setAttribute($startAttribute, $from->getAttribute($startAttribute)); + } + } + } + protected function handleBuiltinTypes(Name $name) + { + $builtinTypes = ['bool' => \true, 'int' => \true, 'float' => \true, 'string' => \true, 'iterable' => \true, 'void' => \true, 'object' => \true, 'null' => \true, 'false' => \true, 'mixed' => \true]; + if (!$name->isUnqualified()) { + return $name; + } + $lowerName = $name->toLowerString(); + if (!isset($builtinTypes[$lowerName])) { + return $name; + } + return new Node\Identifier($lowerName, $name->getAttributes()); + } + /** + * Get combined start and end attributes at a stack location + * + * @param int $pos Stack location + * + * @return array Combined start and end attributes + */ + protected function getAttributesAt($pos) + { + if (!\is_int($pos)) { + if (!(\is_bool($pos) || \is_numeric($pos))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($pos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pos = (int) $pos; + } + } + $phabelReturn = $this->startAttributeStack[$pos] + $this->endAttributeStack[$pos]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + protected function getFloatCastKind($cast) + { + if (!\is_string($cast)) { + if (!(\is_string($cast) || \is_object($cast) && \method_exists($cast, '__toString') || (\is_bool($cast) || \is_numeric($cast)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($cast) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cast) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cast = (string) $cast; + } + } + $cast = \strtolower($cast); + if (\strpos($cast, 'float') !== \false) { + $phabelReturn = Double::KIND_FLOAT; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + if (\strpos($cast, 'real') !== \false) { + $phabelReturn = Double::KIND_REAL; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = Double::KIND_DOUBLE; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + protected function parseLNumber($str, $attributes, $allowInvalidOctal = \false) + { + try { + return LNumber::fromString($str, $attributes, $allowInvalidOctal); + } catch (Error $error) { + $this->emitError($error); + // Use dummy value + return new LNumber(0, $attributes); + } + } + /** + * Parse a T_NUM_STRING token into either an integer or string node. + * + * @param string $str Number string + * @param array $attributes Attributes + * + * @return LNumber|String_ Integer or string node. + */ + protected function parseNumString($str, array $attributes) + { + if (!\is_string($str)) { + if (!(\is_string($str) || \is_object($str) && \method_exists($str, '__toString') || (\is_bool($str) || \is_numeric($str)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($str) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($str) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $str = (string) $str; + } + } + if (!\preg_match('/^(?:0|-?[1-9][0-9]*)$/', $str)) { + return new String_($str, $attributes); + } + $num = +$str; + if (!\is_int($num)) { + return new String_($str, $attributes); + } + return new LNumber($num, $attributes); + } + protected function stripIndentation($string, $indentLen, $indentChar, $newlineAtStart, $newlineAtEnd, array $attributes) + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + if (!\is_int($indentLen)) { + if (!(\is_bool($indentLen) || \is_numeric($indentLen))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($indentLen) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($indentLen) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $indentLen = (int) $indentLen; + } + } + if (!\is_string($indentChar)) { + if (!(\is_string($indentChar) || \is_object($indentChar) && \method_exists($indentChar, '__toString') || (\is_bool($indentChar) || \is_numeric($indentChar)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($indentChar) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($indentChar) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $indentChar = (string) $indentChar; + } + } + if (!\is_bool($newlineAtStart)) { + if (!(\is_bool($newlineAtStart) || \is_numeric($newlineAtStart) || \is_string($newlineAtStart))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($newlineAtStart) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newlineAtStart) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $newlineAtStart = (bool) $newlineAtStart; + } + } + if (!\is_bool($newlineAtEnd)) { + if (!(\is_bool($newlineAtEnd) || \is_numeric($newlineAtEnd) || \is_string($newlineAtEnd))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($newlineAtEnd) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newlineAtEnd) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $newlineAtEnd = (bool) $newlineAtEnd; + } + } + if ($indentLen === 0) { + return $string; + } + $start = $newlineAtStart ? '(?:(?<=\\n)|\\A)' : '(?<=\\n)'; + $end = $newlineAtEnd ? '(?:(?=[\\r\\n])|\\z)' : '(?=[\\r\\n])'; + $regex = '/' . $start . '([ \\t]*)(' . $end . ')?/'; + return \preg_replace_callback($regex, function ($matches) use($indentLen, $indentChar, $attributes) { + $prefix = \substr($matches[1], 0, $indentLen); + if (\false !== \strpos($prefix, $indentChar === " " ? "\t" : " ")) { + $this->emitError(new Error('Invalid indentation - tabs and spaces cannot be mixed', $attributes)); + } elseif (\strlen($prefix) < $indentLen && !isset($matches[2])) { + $this->emitError(new Error('Invalid body indentation level (expecting an indentation level of at least ' . $indentLen . ')', $attributes)); + } + return \substr($matches[0], \strlen($prefix)); + }, $string); + } + protected function parseDocString($startToken, $contents, $endToken, array $attributes, array $endTokenAttributes, $parseUnicodeEscape) + { + if (!\is_string($startToken)) { + if (!(\is_string($startToken) || \is_object($startToken) && \method_exists($startToken, '__toString') || (\is_bool($startToken) || \is_numeric($startToken)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($startToken) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($startToken) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $startToken = (string) $startToken; + } + } + if (!\is_string($endToken)) { + if (!(\is_string($endToken) || \is_object($endToken) && \method_exists($endToken, '__toString') || (\is_bool($endToken) || \is_numeric($endToken)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($endToken) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($endToken) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $endToken = (string) $endToken; + } + } + if (!\is_bool($parseUnicodeEscape)) { + if (!(\is_bool($parseUnicodeEscape) || \is_numeric($parseUnicodeEscape) || \is_string($parseUnicodeEscape))) { + throw new \TypeError(__METHOD__ . '(): Argument #6 ($parseUnicodeEscape) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($parseUnicodeEscape) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $parseUnicodeEscape = (bool) $parseUnicodeEscape; + } + } + $kind = \strpos($startToken, "'") === \false ? String_::KIND_HEREDOC : String_::KIND_NOWDOC; + $regex = '/\\A[bB]?<<<[ \\t]*[\'"]?([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)[\'"]?(?:\\r\\n|\\n|\\r)\\z/'; + $result = \preg_match($regex, $startToken, $matches); + \assert($result === 1); + $label = $matches[1]; + $result = \preg_match('/\\A[ \\t]*/', $endToken, $matches); + \assert($result === 1); + $indentation = $matches[0]; + $attributes['kind'] = $kind; + $attributes['docLabel'] = $label; + $attributes['docIndentation'] = $indentation; + $indentHasSpaces = \false !== \strpos($indentation, " "); + $indentHasTabs = \false !== \strpos($indentation, "\t"); + if ($indentHasSpaces && $indentHasTabs) { + $this->emitError(new Error('Invalid indentation - tabs and spaces cannot be mixed', $endTokenAttributes)); + // Proceed processing as if this doc string is not indented + $indentation = ''; + } + $indentLen = \strlen($indentation); + $indentChar = $indentHasSpaces ? " " : "\t"; + if (\is_string($contents)) { + if ($contents === '') { + return new String_('', $attributes); + } + $contents = $this->stripIndentation($contents, $indentLen, $indentChar, \true, \true, $attributes); + $contents = \preg_replace('~(\\r\\n|\\n|\\r)\\z~', '', $contents); + if ($kind === String_::KIND_HEREDOC) { + $contents = String_::parseEscapeSequences($contents, null, $parseUnicodeEscape); + } + return new String_($contents, $attributes); + } else { + \assert(\count($contents) > 0); + if (!$contents[0] instanceof Node\Scalar\EncapsedStringPart) { + // If there is no leading encapsed string part, pretend there is an empty one + $this->stripIndentation('', $indentLen, $indentChar, \true, \false, $contents[0]->getAttributes()); + } + $newContents = []; + foreach ($contents as $i => $part) { + if ($part instanceof Node\Scalar\EncapsedStringPart) { + $isLast = $i === \count($contents) - 1; + $part->value = $this->stripIndentation($part->value, $indentLen, $indentChar, $i === 0, $isLast, $part->getAttributes()); + $part->value = String_::parseEscapeSequences($part->value, null, $parseUnicodeEscape); + if ($isLast) { + $part->value = \preg_replace('~(\\r\\n|\\n|\\r)\\z~', '', $part->value); + } + if ('' === $part->value) { + continue; + } + } + $newContents[] = $part; + } + return new Encapsed($newContents, $attributes); + } + } + /** + * Create attributes for a zero-length common-capturing nop. + * + * @param Comment[] $comments + * @return array + */ + protected function createCommentNopAttributes(array $comments) + { + $comment = $comments[\count($comments) - 1]; + $commentEndLine = $comment->getEndLine(); + $commentEndFilePos = $comment->getEndFilePos(); + $commentEndTokenPos = $comment->getEndTokenPos(); + $attributes = ['comments' => $comments]; + if (-1 !== $commentEndLine) { + $attributes['startLine'] = $commentEndLine; + $attributes['endLine'] = $commentEndLine; + } + if (-1 !== $commentEndFilePos) { + $attributes['startFilePos'] = $commentEndFilePos + 1; + $attributes['endFilePos'] = $commentEndFilePos; + } + if (-1 !== $commentEndTokenPos) { + $attributes['startTokenPos'] = $commentEndTokenPos + 1; + $attributes['endTokenPos'] = $commentEndTokenPos; + } + return $attributes; + } + protected function checkModifier($a, $b, $modifierPos) + { + // Jumping through some hoops here because verifyModifier() is also used elsewhere + try { + Class_::verifyModifier($a, $b); + } catch (Error $error) { + $error->setAttributes($this->getAttributesAt($modifierPos)); + $this->emitError($error); + } + } + protected function checkParam(Param $node) + { + if ($node->variadic && null !== $node->default) { + $this->emitError(new Error('Variadic parameter cannot have a default value', $node->default->getAttributes())); + } + } + protected function checkTryCatch(TryCatch $node) + { + if (empty($node->catches) && null === $node->finally) { + $this->emitError(new Error('Cannot use try without catch or finally', $node->getAttributes())); + } + } + protected function checkNamespace(Namespace_ $node) + { + if (null !== $node->stmts) { + foreach ($node->stmts as $stmt) { + if ($stmt instanceof Namespace_) { + $this->emitError(new Error('Namespace declarations cannot be nested', $stmt->getAttributes())); + } + } + } + } + protected function checkClass(Class_ $node, $namePos) + { + if (null !== $node->name && $node->name->isSpecialClassName()) { + $this->emitError(new Error(\sprintf('Cannot use \'%s\' as class name as it is reserved', $node->name), $this->getAttributesAt($namePos))); + } + if ($node->extends && $node->extends->isSpecialClassName()) { + $this->emitError(new Error(\sprintf('Cannot use \'%s\' as class name as it is reserved', $node->extends), $node->extends->getAttributes())); + } + foreach ($node->implements as $interface) { + if ($interface->isSpecialClassName()) { + $this->emitError(new Error(\sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface), $interface->getAttributes())); + } + } + } + protected function checkInterface(Interface_ $node, $namePos) + { + if (null !== $node->name && $node->name->isSpecialClassName()) { + $this->emitError(new Error(\sprintf('Cannot use \'%s\' as class name as it is reserved', $node->name), $this->getAttributesAt($namePos))); + } + foreach ($node->extends as $interface) { + if ($interface->isSpecialClassName()) { + $this->emitError(new Error(\sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface), $interface->getAttributes())); + } + } + } + protected function checkClassMethod(ClassMethod $node, $modifierPos) + { + if ($node->flags & Class_::MODIFIER_STATIC) { + switch ($node->name->toLowerString()) { + case '__construct': + $this->emitError(new Error(\sprintf('Constructor %s() cannot be static', $node->name), $this->getAttributesAt($modifierPos))); + break; + case '__destruct': + $this->emitError(new Error(\sprintf('Destructor %s() cannot be static', $node->name), $this->getAttributesAt($modifierPos))); + break; + case '__clone': + $this->emitError(new Error(\sprintf('Clone method %s() cannot be static', $node->name), $this->getAttributesAt($modifierPos))); + break; + } + } + } + protected function checkClassConst(ClassConst $node, $modifierPos) + { + if ($node->flags & Class_::MODIFIER_STATIC) { + $this->emitError(new Error("Cannot use 'static' as constant modifier", $this->getAttributesAt($modifierPos))); + } + if ($node->flags & Class_::MODIFIER_ABSTRACT) { + $this->emitError(new Error("Cannot use 'abstract' as constant modifier", $this->getAttributesAt($modifierPos))); + } + if ($node->flags & Class_::MODIFIER_FINAL) { + $this->emitError(new Error("Cannot use 'final' as constant modifier", $this->getAttributesAt($modifierPos))); + } + } + protected function checkProperty(Property $node, $modifierPos) + { + if ($node->flags & Class_::MODIFIER_ABSTRACT) { + $this->emitError(new Error('Properties cannot be declared abstract', $this->getAttributesAt($modifierPos))); + } + if ($node->flags & Class_::MODIFIER_FINAL) { + $this->emitError(new Error('Properties cannot be declared final', $this->getAttributesAt($modifierPos))); + } + } + protected function checkUseUse(UseUse $node, $namePos) + { + if ($node->alias && $node->alias->isSpecialClassName()) { + $this->emitError(new Error(\sprintf('Cannot use %s as %s because \'%2$s\' is a special class name', $node->name, $node->alias), $this->getAttributesAt($namePos))); + } + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/ParserFactory.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/ParserFactory.php new file mode 100644 index 000000000..804d90541 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/ParserFactory.php @@ -0,0 +1,62 @@ +pAttrGroups($node->attrGroups, \true) . $this->pModifiers($node->flags) . ($node->type ? $this->p($node->type) . ' ' : '') . ($node->byRef ? '&' : '') . ($node->variadic ? '...' : '') . $this->p($node->var) . ($node->default ? ' = ' . $this->p($node->default) : ''); + } + protected function pArg(Node\Arg $node) + { + return ($node->name ? $node->name->toString() . ': ' : '') . ($node->byRef ? '&' : '') . ($node->unpack ? '...' : '') . $this->p($node->value); + } + protected function pConst(Node\Const_ $node) + { + return $node->name . ' = ' . $this->p($node->value); + } + protected function pNullableType(Node\NullableType $node) + { + return '?' . $this->p($node->type); + } + protected function pUnionType(Node\UnionType $node) + { + return $this->pImplode($node->types, '|'); + } + protected function pIdentifier(Node\Identifier $node) + { + return $node->name; + } + protected function pVarLikeIdentifier(Node\VarLikeIdentifier $node) + { + return '$' . $node->name; + } + protected function pAttribute(Node\Attribute $node) + { + return $this->p($node->name) . ($node->args ? '(' . $this->pCommaSeparated($node->args) . ')' : ''); + } + protected function pAttributeGroup(Node\AttributeGroup $node) + { + return '#[' . $this->pCommaSeparated($node->attrs) . ']'; + } + // Names + protected function pName(Name $node) + { + return \implode('\\', $node->parts); + } + protected function pName_FullyQualified(Name\FullyQualified $node) + { + return '\\' . \implode('\\', $node->parts); + } + protected function pName_Relative(Name\Relative $node) + { + return 'namespace\\' . \implode('\\', $node->parts); + } + // Magic Constants + protected function pScalar_MagicConst_Class(MagicConst\Class_ $node) + { + return '__CLASS__'; + } + protected function pScalar_MagicConst_Dir(MagicConst\Dir $node) + { + return '__DIR__'; + } + protected function pScalar_MagicConst_File(MagicConst\File $node) + { + return '__FILE__'; + } + protected function pScalar_MagicConst_Function(MagicConst\Function_ $node) + { + return '__FUNCTION__'; + } + protected function pScalar_MagicConst_Line(MagicConst\Line $node) + { + return '__LINE__'; + } + protected function pScalar_MagicConst_Method(MagicConst\Method $node) + { + return '__METHOD__'; + } + protected function pScalar_MagicConst_Namespace(MagicConst\Namespace_ $node) + { + return '__NAMESPACE__'; + } + protected function pScalar_MagicConst_Trait(MagicConst\Trait_ $node) + { + return '__TRAIT__'; + } + // Scalars + protected function pScalar_String(Scalar\String_ $node) + { + $kind = $node->getAttribute('kind', Scalar\String_::KIND_SINGLE_QUOTED); + switch ($kind) { + case Scalar\String_::KIND_NOWDOC: + $label = $node->getAttribute('docLabel'); + if ($label && !$this->containsEndLabel($node->value, $label)) { + if ($node->value === '') { + return "<<<'{$label}'\n{$label}" . $this->docStringEndToken; + } + return "<<<'{$label}'\n{$node->value}\n{$label}" . $this->docStringEndToken; + } + /* break missing intentionally */ + case Scalar\String_::KIND_SINGLE_QUOTED: + return $this->pSingleQuotedString($node->value); + case Scalar\String_::KIND_HEREDOC: + $label = $node->getAttribute('docLabel'); + if ($label && !$this->containsEndLabel($node->value, $label)) { + if ($node->value === '') { + return "<<<{$label}\n{$label}" . $this->docStringEndToken; + } + $escaped = $this->escapeString($node->value, null); + return "<<<{$label}\n" . $escaped . "\n{$label}" . $this->docStringEndToken; + } + /* break missing intentionally */ + case Scalar\String_::KIND_DOUBLE_QUOTED: + return '"' . $this->escapeString($node->value, '"') . '"'; + } + throw new \Exception('Invalid string kind'); + } + protected function pScalar_Encapsed(Scalar\Encapsed $node) + { + if ($node->getAttribute('kind') === Scalar\String_::KIND_HEREDOC) { + $label = $node->getAttribute('docLabel'); + if ($label && !$this->encapsedContainsEndLabel($node->parts, $label)) { + if (\count($node->parts) === 1 && $node->parts[0] instanceof Scalar\EncapsedStringPart && $node->parts[0]->value === '') { + return "<<<{$label}\n{$label}" . $this->docStringEndToken; + } + return "<<<{$label}\n" . $this->pEncapsList($node->parts, null) . "\n{$label}" . $this->docStringEndToken; + } + } + return '"' . $this->pEncapsList($node->parts, '"') . '"'; + } + protected function pScalar_LNumber(Scalar\LNumber $node) + { + if ($node->value === -\PHP_INT_MAX - 1) { + // PHP_INT_MIN cannot be represented as a literal, + // because the sign is not part of the literal + return '(-' . \PHP_INT_MAX . '-1)'; + } + $kind = $node->getAttribute('kind', Scalar\LNumber::KIND_DEC); + if (Scalar\LNumber::KIND_DEC === $kind) { + return (string) $node->value; + } + if ($node->value < 0) { + $sign = '-'; + $str = (string) -$node->value; + } else { + $sign = ''; + $str = (string) $node->value; + } + switch ($kind) { + case Scalar\LNumber::KIND_BIN: + return $sign . '0b' . \base_convert($str, 10, 2); + case Scalar\LNumber::KIND_OCT: + return $sign . '0' . \base_convert($str, 10, 8); + case Scalar\LNumber::KIND_HEX: + return $sign . '0x' . \base_convert($str, 10, 16); + } + throw new \Exception('Invalid number kind'); + } + protected function pScalar_DNumber(Scalar\DNumber $node) + { + if (!\is_finite($node->value)) { + if ($node->value === \INF) { + return '\\INF'; + } elseif ($node->value === -\INF) { + return '-\\INF'; + } else { + return '\\NAN'; + } + } + // Try to find a short full-precision representation + $stringValue = \sprintf('%.16G', $node->value); + if ($node->value !== (double) $stringValue) { + $stringValue = \sprintf('%.17G', $node->value); + } + // %G is locale dependent and there exists no locale-independent alternative. We don't want + // mess with switching locales here, so let's assume that a comma is the only non-standard + // decimal separator we may encounter... + $stringValue = \str_replace(',', '.', $stringValue); + // ensure that number is really printed as float + return \preg_match('/^-?[0-9]+$/', $stringValue) ? $stringValue . '.0' : $stringValue; + } + protected function pScalar_EncapsedStringPart(Scalar\EncapsedStringPart $node) + { + throw new \LogicException('Cannot directly print EncapsedStringPart'); + } + // Assignments + protected function pExpr_Assign(Expr\Assign $node) + { + return $this->pInfixOp(Expr\Assign::class, $node->var, ' = ', $node->expr); + } + protected function pExpr_AssignRef(Expr\AssignRef $node) + { + return $this->pInfixOp(Expr\AssignRef::class, $node->var, ' =& ', $node->expr); + } + protected function pExpr_AssignOp_Plus(AssignOp\Plus $node) + { + return $this->pInfixOp(AssignOp\Plus::class, $node->var, ' += ', $node->expr); + } + protected function pExpr_AssignOp_Minus(AssignOp\Minus $node) + { + return $this->pInfixOp(AssignOp\Minus::class, $node->var, ' -= ', $node->expr); + } + protected function pExpr_AssignOp_Mul(AssignOp\Mul $node) + { + return $this->pInfixOp(AssignOp\Mul::class, $node->var, ' *= ', $node->expr); + } + protected function pExpr_AssignOp_Div(AssignOp\Div $node) + { + return $this->pInfixOp(AssignOp\Div::class, $node->var, ' /= ', $node->expr); + } + protected function pExpr_AssignOp_Concat(AssignOp\Concat $node) + { + return $this->pInfixOp(AssignOp\Concat::class, $node->var, ' .= ', $node->expr); + } + protected function pExpr_AssignOp_Mod(AssignOp\Mod $node) + { + return $this->pInfixOp(AssignOp\Mod::class, $node->var, ' %= ', $node->expr); + } + protected function pExpr_AssignOp_BitwiseAnd(AssignOp\BitwiseAnd $node) + { + return $this->pInfixOp(AssignOp\BitwiseAnd::class, $node->var, ' &= ', $node->expr); + } + protected function pExpr_AssignOp_BitwiseOr(AssignOp\BitwiseOr $node) + { + return $this->pInfixOp(AssignOp\BitwiseOr::class, $node->var, ' |= ', $node->expr); + } + protected function pExpr_AssignOp_BitwiseXor(AssignOp\BitwiseXor $node) + { + return $this->pInfixOp(AssignOp\BitwiseXor::class, $node->var, ' ^= ', $node->expr); + } + protected function pExpr_AssignOp_ShiftLeft(AssignOp\ShiftLeft $node) + { + return $this->pInfixOp(AssignOp\ShiftLeft::class, $node->var, ' <<= ', $node->expr); + } + protected function pExpr_AssignOp_ShiftRight(AssignOp\ShiftRight $node) + { + return $this->pInfixOp(AssignOp\ShiftRight::class, $node->var, ' >>= ', $node->expr); + } + protected function pExpr_AssignOp_Pow(AssignOp\Pow $node) + { + return $this->pInfixOp(AssignOp\Pow::class, $node->var, ' **= ', $node->expr); + } + protected function pExpr_AssignOp_Coalesce(AssignOp\Coalesce $node) + { + return $this->pInfixOp(AssignOp\Coalesce::class, $node->var, ' ??= ', $node->expr); + } + // Binary expressions + protected function pExpr_BinaryOp_Plus(BinaryOp\Plus $node) + { + return $this->pInfixOp(BinaryOp\Plus::class, $node->left, ' + ', $node->right); + } + protected function pExpr_BinaryOp_Minus(BinaryOp\Minus $node) + { + return $this->pInfixOp(BinaryOp\Minus::class, $node->left, ' - ', $node->right); + } + protected function pExpr_BinaryOp_Mul(BinaryOp\Mul $node) + { + return $this->pInfixOp(BinaryOp\Mul::class, $node->left, ' * ', $node->right); + } + protected function pExpr_BinaryOp_Div(BinaryOp\Div $node) + { + return $this->pInfixOp(BinaryOp\Div::class, $node->left, ' / ', $node->right); + } + protected function pExpr_BinaryOp_Concat(BinaryOp\Concat $node) + { + return $this->pInfixOp(BinaryOp\Concat::class, $node->left, ' . ', $node->right); + } + protected function pExpr_BinaryOp_Mod(BinaryOp\Mod $node) + { + return $this->pInfixOp(BinaryOp\Mod::class, $node->left, ' % ', $node->right); + } + protected function pExpr_BinaryOp_BooleanAnd(BinaryOp\BooleanAnd $node) + { + return $this->pInfixOp(BinaryOp\BooleanAnd::class, $node->left, ' && ', $node->right); + } + protected function pExpr_BinaryOp_BooleanOr(BinaryOp\BooleanOr $node) + { + return $this->pInfixOp(BinaryOp\BooleanOr::class, $node->left, ' || ', $node->right); + } + protected function pExpr_BinaryOp_BitwiseAnd(BinaryOp\BitwiseAnd $node) + { + return $this->pInfixOp(BinaryOp\BitwiseAnd::class, $node->left, ' & ', $node->right); + } + protected function pExpr_BinaryOp_BitwiseOr(BinaryOp\BitwiseOr $node) + { + return $this->pInfixOp(BinaryOp\BitwiseOr::class, $node->left, ' | ', $node->right); + } + protected function pExpr_BinaryOp_BitwiseXor(BinaryOp\BitwiseXor $node) + { + return $this->pInfixOp(BinaryOp\BitwiseXor::class, $node->left, ' ^ ', $node->right); + } + protected function pExpr_BinaryOp_ShiftLeft(BinaryOp\ShiftLeft $node) + { + return $this->pInfixOp(BinaryOp\ShiftLeft::class, $node->left, ' << ', $node->right); + } + protected function pExpr_BinaryOp_ShiftRight(BinaryOp\ShiftRight $node) + { + return $this->pInfixOp(BinaryOp\ShiftRight::class, $node->left, ' >> ', $node->right); + } + protected function pExpr_BinaryOp_Pow(BinaryOp\Pow $node) + { + return $this->pInfixOp(BinaryOp\Pow::class, $node->left, ' ** ', $node->right); + } + protected function pExpr_BinaryOp_LogicalAnd(BinaryOp\LogicalAnd $node) + { + return $this->pInfixOp(BinaryOp\LogicalAnd::class, $node->left, ' and ', $node->right); + } + protected function pExpr_BinaryOp_LogicalOr(BinaryOp\LogicalOr $node) + { + return $this->pInfixOp(BinaryOp\LogicalOr::class, $node->left, ' or ', $node->right); + } + protected function pExpr_BinaryOp_LogicalXor(BinaryOp\LogicalXor $node) + { + return $this->pInfixOp(BinaryOp\LogicalXor::class, $node->left, ' xor ', $node->right); + } + protected function pExpr_BinaryOp_Equal(BinaryOp\Equal $node) + { + return $this->pInfixOp(BinaryOp\Equal::class, $node->left, ' == ', $node->right); + } + protected function pExpr_BinaryOp_NotEqual(BinaryOp\NotEqual $node) + { + return $this->pInfixOp(BinaryOp\NotEqual::class, $node->left, ' != ', $node->right); + } + protected function pExpr_BinaryOp_Identical(BinaryOp\Identical $node) + { + return $this->pInfixOp(BinaryOp\Identical::class, $node->left, ' === ', $node->right); + } + protected function pExpr_BinaryOp_NotIdentical(BinaryOp\NotIdentical $node) + { + return $this->pInfixOp(BinaryOp\NotIdentical::class, $node->left, ' !== ', $node->right); + } + protected function pExpr_BinaryOp_Spaceship(BinaryOp\Spaceship $node) + { + return $this->pInfixOp(BinaryOp\Spaceship::class, $node->left, ' <=> ', $node->right); + } + protected function pExpr_BinaryOp_Greater(BinaryOp\Greater $node) + { + return $this->pInfixOp(BinaryOp\Greater::class, $node->left, ' > ', $node->right); + } + protected function pExpr_BinaryOp_GreaterOrEqual(BinaryOp\GreaterOrEqual $node) + { + return $this->pInfixOp(BinaryOp\GreaterOrEqual::class, $node->left, ' >= ', $node->right); + } + protected function pExpr_BinaryOp_Smaller(BinaryOp\Smaller $node) + { + return $this->pInfixOp(BinaryOp\Smaller::class, $node->left, ' < ', $node->right); + } + protected function pExpr_BinaryOp_SmallerOrEqual(BinaryOp\SmallerOrEqual $node) + { + return $this->pInfixOp(BinaryOp\SmallerOrEqual::class, $node->left, ' <= ', $node->right); + } + protected function pExpr_BinaryOp_Coalesce(BinaryOp\Coalesce $node) + { + return $this->pInfixOp(BinaryOp\Coalesce::class, $node->left, ' ?? ', $node->right); + } + protected function pExpr_Instanceof(Expr\Instanceof_ $node) + { + list($precedence, $associativity) = $this->precedenceMap[Expr\Instanceof_::class]; + return $this->pPrec($node->expr, $precedence, $associativity, -1) . ' instanceof ' . $this->pNewVariable($node->class); + } + // Unary expressions + protected function pExpr_BooleanNot(Expr\BooleanNot $node) + { + return $this->pPrefixOp(Expr\BooleanNot::class, '!', $node->expr); + } + protected function pExpr_BitwiseNot(Expr\BitwiseNot $node) + { + return $this->pPrefixOp(Expr\BitwiseNot::class, '~', $node->expr); + } + protected function pExpr_UnaryMinus(Expr\UnaryMinus $node) + { + if ($node->expr instanceof Expr\UnaryMinus || $node->expr instanceof Expr\PreDec) { + // Enforce -(-$expr) instead of --$expr + return '-(' . $this->p($node->expr) . ')'; + } + return $this->pPrefixOp(Expr\UnaryMinus::class, '-', $node->expr); + } + protected function pExpr_UnaryPlus(Expr\UnaryPlus $node) + { + if ($node->expr instanceof Expr\UnaryPlus || $node->expr instanceof Expr\PreInc) { + // Enforce +(+$expr) instead of ++$expr + return '+(' . $this->p($node->expr) . ')'; + } + return $this->pPrefixOp(Expr\UnaryPlus::class, '+', $node->expr); + } + protected function pExpr_PreInc(Expr\PreInc $node) + { + return $this->pPrefixOp(Expr\PreInc::class, '++', $node->var); + } + protected function pExpr_PreDec(Expr\PreDec $node) + { + return $this->pPrefixOp(Expr\PreDec::class, '--', $node->var); + } + protected function pExpr_PostInc(Expr\PostInc $node) + { + return $this->pPostfixOp(Expr\PostInc::class, $node->var, '++'); + } + protected function pExpr_PostDec(Expr\PostDec $node) + { + return $this->pPostfixOp(Expr\PostDec::class, $node->var, '--'); + } + protected function pExpr_ErrorSuppress(Expr\ErrorSuppress $node) + { + return $this->pPrefixOp(Expr\ErrorSuppress::class, '@', $node->expr); + } + protected function pExpr_YieldFrom(Expr\YieldFrom $node) + { + return $this->pPrefixOp(Expr\YieldFrom::class, 'yield from ', $node->expr); + } + protected function pExpr_Print(Expr\Print_ $node) + { + return $this->pPrefixOp(Expr\Print_::class, 'print ', $node->expr); + } + // Casts + protected function pExpr_Cast_Int(Cast\Int_ $node) + { + return $this->pPrefixOp(Cast\Int_::class, '(int) ', $node->expr); + } + protected function pExpr_Cast_Double(Cast\Double $node) + { + $kind = $node->getAttribute('kind', Cast\Double::KIND_DOUBLE); + if ($kind === Cast\Double::KIND_DOUBLE) { + $cast = '(double)'; + } elseif ($kind === Cast\Double::KIND_FLOAT) { + $cast = '(float)'; + } elseif ($kind === Cast\Double::KIND_REAL) { + $cast = '(real)'; + } + return $this->pPrefixOp(Cast\Double::class, $cast . ' ', $node->expr); + } + protected function pExpr_Cast_String(Cast\String_ $node) + { + return $this->pPrefixOp(Cast\String_::class, '(string) ', $node->expr); + } + protected function pExpr_Cast_Array(Cast\Array_ $node) + { + return $this->pPrefixOp(Cast\Array_::class, '(array) ', $node->expr); + } + protected function pExpr_Cast_Object(Cast\Object_ $node) + { + return $this->pPrefixOp(Cast\Object_::class, '(object) ', $node->expr); + } + protected function pExpr_Cast_Bool(Cast\Bool_ $node) + { + return $this->pPrefixOp(Cast\Bool_::class, '(bool) ', $node->expr); + } + protected function pExpr_Cast_Unset(Cast\Unset_ $node) + { + return $this->pPrefixOp(Cast\Unset_::class, '(unset) ', $node->expr); + } + // Function calls and similar constructs + protected function pExpr_FuncCall(Expr\FuncCall $node) + { + return $this->pCallLhs($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_MethodCall(Expr\MethodCall $node) + { + return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_NullsafeMethodCall(Expr\NullsafeMethodCall $node) + { + return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_StaticCall(Expr\StaticCall $node) + { + return $this->pDereferenceLhs($node->class) . '::' . ($node->name instanceof Expr ? $node->name instanceof Expr\Variable ? $this->p($node->name) : '{' . $this->p($node->name) . '}' : $node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_Empty(Expr\Empty_ $node) + { + return 'empty(' . $this->p($node->expr) . ')'; + } + protected function pExpr_Isset(Expr\Isset_ $node) + { + return 'isset(' . $this->pCommaSeparated($node->vars) . ')'; + } + protected function pExpr_Eval(Expr\Eval_ $node) + { + return 'eval(' . $this->p($node->expr) . ')'; + } + protected function pExpr_Include(Expr\Include_ $node) + { + static $map = [Expr\Include_::TYPE_INCLUDE => 'include', Expr\Include_::TYPE_INCLUDE_ONCE => 'include_once', Expr\Include_::TYPE_REQUIRE => 'require', Expr\Include_::TYPE_REQUIRE_ONCE => 'require_once']; + return $map[$node->type] . ' ' . $this->p($node->expr); + } + protected function pExpr_List(Expr\List_ $node) + { + return 'list(' . $this->pCommaSeparated($node->items) . ')'; + } + // Other + protected function pExpr_Error(Expr\Error $node) + { + throw new \LogicException('Cannot pretty-print AST with Error nodes'); + } + protected function pExpr_Variable(Expr\Variable $node) + { + if ($node->name instanceof Expr) { + return '${' . $this->p($node->name) . '}'; + } else { + return '$' . $node->name; + } + } + protected function pExpr_Array(Expr\Array_ $node) + { + $syntax = $node->getAttribute('kind', $this->options['shortArraySyntax'] ? Expr\Array_::KIND_SHORT : Expr\Array_::KIND_LONG); + if ($syntax === Expr\Array_::KIND_SHORT) { + return '[' . $this->pMaybeMultiline($node->items, \true) . ']'; + } else { + return 'array(' . $this->pMaybeMultiline($node->items, \true) . ')'; + } + } + protected function pExpr_ArrayItem(Expr\ArrayItem $node) + { + return (null !== $node->key ? $this->p($node->key) . ' => ' : '') . ($node->byRef ? '&' : '') . ($node->unpack ? '...' : '') . $this->p($node->value); + } + protected function pExpr_ArrayDimFetch(Expr\ArrayDimFetch $node) + { + return $this->pDereferenceLhs($node->var) . '[' . (null !== $node->dim ? $this->p($node->dim) : '') . ']'; + } + protected function pExpr_ConstFetch(Expr\ConstFetch $node) + { + return $this->p($node->name); + } + protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) + { + return $this->pDereferenceLhs($node->class) . '::' . $this->p($node->name); + } + protected function pExpr_PropertyFetch(Expr\PropertyFetch $node) + { + return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name); + } + protected function pExpr_NullsafePropertyFetch(Expr\NullsafePropertyFetch $node) + { + return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name); + } + protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) + { + return $this->pDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name); + } + protected function pExpr_ShellExec(Expr\ShellExec $node) + { + return '`' . $this->pEncapsList($node->parts, '`') . '`'; + } + protected function pExpr_Closure(Expr\Closure $node) + { + return $this->pAttrGroups($node->attrGroups, \true) . ($node->static ? 'static ' : '') . 'function ' . ($node->byRef ? '&' : '') . '(' . $this->pCommaSeparated($node->params) . ')' . (!empty($node->uses) ? ' use(' . $this->pCommaSeparated($node->uses) . ')' : '') . (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '') . ' {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pExpr_Match(Expr\Match_ $node) + { + return 'match (' . $this->p($node->cond) . ') {' . $this->pCommaSeparatedMultiline($node->arms, \true) . $this->nl . '}'; + } + protected function pMatchArm(Node\MatchArm $node) + { + return ($node->conds ? $this->pCommaSeparated($node->conds) : 'default') . ' => ' . $this->p($node->body); + } + protected function pExpr_ArrowFunction(Expr\ArrowFunction $node) + { + return $this->pAttrGroups($node->attrGroups, \true) . ($node->static ? 'static ' : '') . 'fn' . ($node->byRef ? '&' : '') . '(' . $this->pCommaSeparated($node->params) . ')' . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '') . ' => ' . $this->pDereferenceLhs($node->expr); + } + protected function pExpr_ClosureUse(Expr\ClosureUse $node) + { + return ($node->byRef ? '&' : '') . $this->p($node->var); + } + protected function pExpr_New(Expr\New_ $node) + { + if ($node->class instanceof Stmt\Class_) { + $args = $node->args ? '(' . $this->pMaybeMultiline($node->args) . ')' : ''; + return 'new ' . $this->pClassCommon($node->class, $args); + } + return 'new ' . $this->pNewVariable($node->class) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_Clone(Expr\Clone_ $node) + { + return 'clone ' . $this->p($node->expr); + } + protected function pExpr_Ternary(Expr\Ternary $node) + { + // a bit of cheating: we treat the ternary as a binary op where the ?...: part is the operator. + // this is okay because the part between ? and : never needs parentheses. + return $this->pInfixOp(Expr\Ternary::class, $node->cond, ' ?' . (null !== $node->if ? ' ' . $this->p($node->if) . ' ' : '') . ': ', $node->else); + } + protected function pExpr_Exit(Expr\Exit_ $node) + { + $kind = $node->getAttribute('kind', Expr\Exit_::KIND_DIE); + return ($kind === Expr\Exit_::KIND_EXIT ? 'exit' : 'die') . (null !== $node->expr ? '(' . $this->p($node->expr) . ')' : ''); + } + protected function pExpr_Throw(Expr\Throw_ $node) + { + return 'throw ' . $this->p($node->expr); + } + protected function pExpr_Yield(Expr\Yield_ $node) + { + if ($node->value === null) { + return 'yield'; + } else { + // this is a bit ugly, but currently there is no way to detect whether the parentheses are necessary + return '(yield ' . ($node->key !== null ? $this->p($node->key) . ' => ' : '') . $this->p($node->value) . ')'; + } + } + // Declarations + protected function pStmt_Namespace(Stmt\Namespace_ $node) + { + if ($this->canUseSemicolonNamespaces) { + return 'namespace ' . $this->p($node->name) . ';' . $this->nl . $this->pStmts($node->stmts, \false); + } else { + return 'namespace' . (null !== $node->name ? ' ' . $this->p($node->name) : '') . ' {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + } + protected function pStmt_Use(Stmt\Use_ $node) + { + return 'use ' . $this->pUseType($node->type) . $this->pCommaSeparated($node->uses) . ';'; + } + protected function pStmt_GroupUse(Stmt\GroupUse $node) + { + return 'use ' . $this->pUseType($node->type) . $this->pName($node->prefix) . '\\{' . $this->pCommaSeparated($node->uses) . '};'; + } + protected function pStmt_UseUse(Stmt\UseUse $node) + { + return $this->pUseType($node->type) . $this->p($node->name) . (null !== $node->alias ? ' as ' . $node->alias : ''); + } + protected function pUseType($type) + { + return $type === Stmt\Use_::TYPE_FUNCTION ? 'function ' : ($type === Stmt\Use_::TYPE_CONSTANT ? 'const ' : ''); + } + protected function pStmt_Interface(Stmt\Interface_ $node) + { + return $this->pAttrGroups($node->attrGroups) . 'interface ' . $node->name . (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Class(Stmt\Class_ $node) + { + return $this->pClassCommon($node, ' ' . $node->name); + } + protected function pStmt_Trait(Stmt\Trait_ $node) + { + return $this->pAttrGroups($node->attrGroups) . 'trait ' . $node->name . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_TraitUse(Stmt\TraitUse $node) + { + return 'use ' . $this->pCommaSeparated($node->traits) . (empty($node->adaptations) ? ';' : ' {' . $this->pStmts($node->adaptations) . $this->nl . '}'); + } + protected function pStmt_TraitUseAdaptation_Precedence(Stmt\TraitUseAdaptation\Precedence $node) + { + return $this->p($node->trait) . '::' . $node->method . ' insteadof ' . $this->pCommaSeparated($node->insteadof) . ';'; + } + protected function pStmt_TraitUseAdaptation_Alias(Stmt\TraitUseAdaptation\Alias $node) + { + return (null !== $node->trait ? $this->p($node->trait) . '::' : '') . $node->method . ' as' . (null !== $node->newModifier ? ' ' . \rtrim($this->pModifiers($node->newModifier), ' ') : '') . (null !== $node->newName ? ' ' . $node->newName : '') . ';'; + } + protected function pStmt_Property(Stmt\Property $node) + { + return $this->pAttrGroups($node->attrGroups) . (0 === $node->flags ? 'var ' : $this->pModifiers($node->flags)) . ($node->type ? $this->p($node->type) . ' ' : '') . $this->pCommaSeparated($node->props) . ';'; + } + protected function pStmt_PropertyProperty(Stmt\PropertyProperty $node) + { + return '$' . $node->name . (null !== $node->default ? ' = ' . $this->p($node->default) : ''); + } + protected function pStmt_ClassMethod(Stmt\ClassMethod $node) + { + return $this->pAttrGroups($node->attrGroups) . $this->pModifiers($node->flags) . 'function ' . ($node->byRef ? '&' : '') . $node->name . '(' . $this->pMaybeMultiline($node->params) . ')' . (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '') . (null !== $node->stmts ? $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}' : ';'); + } + protected function pStmt_ClassConst(Stmt\ClassConst $node) + { + return $this->pAttrGroups($node->attrGroups) . $this->pModifiers($node->flags) . 'const ' . $this->pCommaSeparated($node->consts) . ';'; + } + protected function pStmt_Function(Stmt\Function_ $node) + { + return $this->pAttrGroups($node->attrGroups) . 'function ' . ($node->byRef ? '&' : '') . $node->name . '(' . $this->pCommaSeparated($node->params) . ')' . (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Const(Stmt\Const_ $node) + { + return 'const ' . $this->pCommaSeparated($node->consts) . ';'; + } + protected function pStmt_Declare(Stmt\Declare_ $node) + { + return 'declare (' . $this->pCommaSeparated($node->declares) . ')' . (null !== $node->stmts ? ' {' . $this->pStmts($node->stmts) . $this->nl . '}' : ';'); + } + protected function pStmt_DeclareDeclare(Stmt\DeclareDeclare $node) + { + return $node->key . '=' . $this->p($node->value); + } + // Control flow + protected function pStmt_If(Stmt\If_ $node) + { + return 'if (' . $this->p($node->cond) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}' . ($node->elseifs ? ' ' . $this->pImplode($node->elseifs, ' ') : '') . (null !== $node->else ? ' ' . $this->p($node->else) : ''); + } + protected function pStmt_ElseIf(Stmt\ElseIf_ $node) + { + return 'elseif (' . $this->p($node->cond) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Else(Stmt\Else_ $node) + { + return 'else {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_For(Stmt\For_ $node) + { + return 'for (' . $this->pCommaSeparated($node->init) . ';' . (!empty($node->cond) ? ' ' : '') . $this->pCommaSeparated($node->cond) . ';' . (!empty($node->loop) ? ' ' : '') . $this->pCommaSeparated($node->loop) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Foreach(Stmt\Foreach_ $node) + { + return 'foreach (' . $this->p($node->expr) . ' as ' . (null !== $node->keyVar ? $this->p($node->keyVar) . ' => ' : '') . ($node->byRef ? '&' : '') . $this->p($node->valueVar) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_While(Stmt\While_ $node) + { + return 'while (' . $this->p($node->cond) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Do(Stmt\Do_ $node) + { + return 'do {' . $this->pStmts($node->stmts) . $this->nl . '} while (' . $this->p($node->cond) . ');'; + } + protected function pStmt_Switch(Stmt\Switch_ $node) + { + return 'switch (' . $this->p($node->cond) . ') {' . $this->pStmts($node->cases) . $this->nl . '}'; + } + protected function pStmt_Case(Stmt\Case_ $node) + { + return (null !== $node->cond ? 'case ' . $this->p($node->cond) : 'default') . ':' . $this->pStmts($node->stmts); + } + protected function pStmt_TryCatch(Stmt\TryCatch $node) + { + return 'try {' . $this->pStmts($node->stmts) . $this->nl . '}' . ($node->catches ? ' ' . $this->pImplode($node->catches, ' ') : '') . ($node->finally !== null ? ' ' . $this->p($node->finally) : ''); + } + protected function pStmt_Catch(Stmt\Catch_ $node) + { + return 'catch (' . $this->pImplode($node->types, '|') . ($node->var !== null ? ' ' . $this->p($node->var) : '') . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Finally(Stmt\Finally_ $node) + { + return 'finally {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Break(Stmt\Break_ $node) + { + return 'break' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';'; + } + protected function pStmt_Continue(Stmt\Continue_ $node) + { + return 'continue' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';'; + } + protected function pStmt_Return(Stmt\Return_ $node) + { + return 'return' . (null !== $node->expr ? ' ' . $this->p($node->expr) : '') . ';'; + } + protected function pStmt_Throw(Stmt\Throw_ $node) + { + return 'throw ' . $this->p($node->expr) . ';'; + } + protected function pStmt_Label(Stmt\Label $node) + { + return $node->name . ':'; + } + protected function pStmt_Goto(Stmt\Goto_ $node) + { + return 'goto ' . $node->name . ';'; + } + // Other + protected function pStmt_Expression(Stmt\Expression $node) + { + return $this->p($node->expr) . ';'; + } + protected function pStmt_Echo(Stmt\Echo_ $node) + { + return 'echo ' . $this->pCommaSeparated($node->exprs) . ';'; + } + protected function pStmt_Static(Stmt\Static_ $node) + { + return 'static ' . $this->pCommaSeparated($node->vars) . ';'; + } + protected function pStmt_Global(Stmt\Global_ $node) + { + return 'global ' . $this->pCommaSeparated($node->vars) . ';'; + } + protected function pStmt_StaticVar(Stmt\StaticVar $node) + { + return $this->p($node->var) . (null !== $node->default ? ' = ' . $this->p($node->default) : ''); + } + protected function pStmt_Unset(Stmt\Unset_ $node) + { + return 'unset(' . $this->pCommaSeparated($node->vars) . ');'; + } + protected function pStmt_InlineHTML(Stmt\InlineHTML $node) + { + $newline = $node->getAttribute('hasLeadingNewline', \true) ? "\n" : ''; + return '?>' . $newline . $node->value . 'remaining; + } + protected function pStmt_Nop(Stmt\Nop $node) + { + return ''; + } + // Helpers + protected function pClassCommon(Stmt\Class_ $node, $afterClassToken) + { + return $this->pAttrGroups($node->attrGroups, $node->name === null) . $this->pModifiers($node->flags) . 'class' . $afterClassToken . (null !== $node->extends ? ' extends ' . $this->p($node->extends) : '') . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pObjectProperty($node) + { + if ($node instanceof Expr) { + return '{' . $this->p($node) . '}'; + } else { + return $node; + } + } + protected function pEncapsList(array $encapsList, $quote) + { + $return = ''; + foreach ($encapsList as $element) { + if ($element instanceof Scalar\EncapsedStringPart) { + $return .= $this->escapeString($element->value, $quote); + } else { + $return .= '{' . $this->p($element) . '}'; + } + } + return $return; + } + protected function pSingleQuotedString($string) + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + return '\'' . \addcslashes($string, '\'\\') . '\''; + } + protected function escapeString($string, $quote) + { + if (null === $quote) { + // For doc strings, don't escape newlines + $escaped = \addcslashes($string, "\t\f\v\$\\"); + } else { + $escaped = \addcslashes($string, "\n\r\t\f\v\$" . $quote . "\\"); + } + // Escape other control characters + return \preg_replace_callback('/([\\0-\\10\\16-\\37])(?=([0-7]?))/', function ($matches) { + $oct = \decoct(\ord($matches[1])); + if ($matches[2] !== '') { + // If there is a trailing digit, use the full three character form + return '\\' . \str_pad($oct, 3, '0', \STR_PAD_LEFT); + } + return '\\' . $oct; + }, $escaped); + } + protected function containsEndLabel($string, $label, $atStart = \true, $atEnd = \true) + { + $start = $atStart ? '(?:^|[\\r\\n])' : '[\\r\\n]'; + $end = $atEnd ? '(?:$|[;\\r\\n])' : '[;\\r\\n]'; + return \false !== \strpos($string, $label) && \preg_match('/' . $start . $label . $end . '/', $string); + } + protected function encapsedContainsEndLabel(array $parts, $label) + { + foreach ($parts as $i => $part) { + $atStart = $i === 0; + $atEnd = $i === \count($parts) - 1; + if ($part instanceof Scalar\EncapsedStringPart && $this->containsEndLabel($part->value, $label, $atStart, $atEnd)) { + return \true; + } + } + return \false; + } + protected function pDereferenceLhs(Node $node) + { + if (!$this->dereferenceLhsRequiresParens($node)) { + return $this->p($node); + } else { + return '(' . $this->p($node) . ')'; + } + } + protected function pCallLhs(Node $node) + { + if (!$this->callLhsRequiresParens($node)) { + return $this->p($node); + } else { + return '(' . $this->p($node) . ')'; + } + } + protected function pNewVariable(Node $node) + { + if (!$node instanceof Scalar\String_) { + return $this->pDereferenceLhs($node); + } else { + return '(' . $this->p($node) . ')'; + } + } + /** + * @param Node[] $nodes + * @return bool + */ + protected function hasNodeWithComments(array $nodes) + { + foreach ($nodes as $node) { + if ($node && $node->getComments()) { + return \true; + } + } + return \false; + } + protected function pMaybeMultiline(array $nodes, $trailingComma = \false) + { + if (!\is_bool($trailingComma)) { + if (!(\is_bool($trailingComma) || \is_numeric($trailingComma) || \is_string($trailingComma))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($trailingComma) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($trailingComma) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $trailingComma = (bool) $trailingComma; + } + } + if (!$this->hasNodeWithComments($nodes)) { + return $this->pCommaSeparated($nodes); + } else { + return $this->pCommaSeparatedMultiline($nodes, $trailingComma) . $this->nl; + } + } + protected function pAttrGroups(array $nodes, $inline = \false) + { + if (!\is_bool($inline)) { + if (!(\is_bool($inline) || \is_numeric($inline) || \is_string($inline))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($inline) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($inline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $inline = (bool) $inline; + } + } + $result = ''; + $sep = $inline ? ' ' : $this->nl; + foreach ($nodes as $node) { + $result .= $this->p($node) . $sep; + } + $phabelReturn = $result; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/phabel/php-parser/lib/PhpParser/PrettyPrinterAbstract.php b/vendor-bundle/phabel/php-parser/lib/PhpParser/PrettyPrinterAbstract.php new file mode 100644 index 000000000..9a12745c6 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/lib/PhpParser/PrettyPrinterAbstract.php @@ -0,0 +1,1668 @@ + [0, 1], + Expr\BitwiseNot::class => [10, 1], + Expr\PreInc::class => [10, 1], + Expr\PreDec::class => [10, 1], + Expr\PostInc::class => [10, -1], + Expr\PostDec::class => [10, -1], + Expr\UnaryPlus::class => [10, 1], + Expr\UnaryMinus::class => [10, 1], + Cast\Int_::class => [10, 1], + Cast\Double::class => [10, 1], + Cast\String_::class => [10, 1], + Cast\Array_::class => [10, 1], + Cast\Object_::class => [10, 1], + Cast\Bool_::class => [10, 1], + Cast\Unset_::class => [10, 1], + Expr\ErrorSuppress::class => [10, 1], + Expr\Instanceof_::class => [20, 0], + Expr\BooleanNot::class => [30, 1], + BinaryOp\Mul::class => [40, -1], + BinaryOp\Div::class => [40, -1], + BinaryOp\Mod::class => [40, -1], + BinaryOp\Plus::class => [50, -1], + BinaryOp\Minus::class => [50, -1], + BinaryOp\Concat::class => [50, -1], + BinaryOp\ShiftLeft::class => [60, -1], + BinaryOp\ShiftRight::class => [60, -1], + BinaryOp\Smaller::class => [70, 0], + BinaryOp\SmallerOrEqual::class => [70, 0], + BinaryOp\Greater::class => [70, 0], + BinaryOp\GreaterOrEqual::class => [70, 0], + BinaryOp\Equal::class => [80, 0], + BinaryOp\NotEqual::class => [80, 0], + BinaryOp\Identical::class => [80, 0], + BinaryOp\NotIdentical::class => [80, 0], + BinaryOp\Spaceship::class => [80, 0], + BinaryOp\BitwiseAnd::class => [90, -1], + BinaryOp\BitwiseXor::class => [100, -1], + BinaryOp\BitwiseOr::class => [110, -1], + BinaryOp\BooleanAnd::class => [120, -1], + BinaryOp\BooleanOr::class => [130, -1], + BinaryOp\Coalesce::class => [140, 1], + Expr\Ternary::class => [150, 0], + // parser uses %left for assignments, but they really behave as %right + Expr\Assign::class => [160, 1], + Expr\AssignRef::class => [160, 1], + AssignOp\Plus::class => [160, 1], + AssignOp\Minus::class => [160, 1], + AssignOp\Mul::class => [160, 1], + AssignOp\Div::class => [160, 1], + AssignOp\Concat::class => [160, 1], + AssignOp\Mod::class => [160, 1], + AssignOp\BitwiseAnd::class => [160, 1], + AssignOp\BitwiseOr::class => [160, 1], + AssignOp\BitwiseXor::class => [160, 1], + AssignOp\ShiftLeft::class => [160, 1], + AssignOp\ShiftRight::class => [160, 1], + AssignOp\Pow::class => [160, 1], + AssignOp\Coalesce::class => [160, 1], + Expr\YieldFrom::class => [165, 1], + Expr\Print_::class => [168, 1], + BinaryOp\LogicalAnd::class => [170, -1], + BinaryOp\LogicalXor::class => [180, -1], + BinaryOp\LogicalOr::class => [190, -1], + Expr\Include_::class => [200, -1], + ]; + /** @var int Current indentation level. */ + protected $indentLevel; + /** @var string Newline including current indentation. */ + protected $nl; + /** @var string Token placed at end of doc string to ensure it is followed by a newline. */ + protected $docStringEndToken; + /** @var bool Whether semicolon namespaces can be used (i.e. no global namespace is used) */ + protected $canUseSemicolonNamespaces; + /** @var array Pretty printer options */ + protected $options; + /** @var TokenStream Original tokens for use in format-preserving pretty print */ + protected $origTokens; + /** @var Internal\Differ Differ for node lists */ + protected $nodeListDiffer; + /** @var bool[] Map determining whether a certain character is a label character */ + protected $labelCharMap; + /** + * @var int[][] Map from token classes and subnode names to FIXUP_* constants. This is used + * during format-preserving prints to place additional parens/braces if necessary. + */ + protected $fixupMap; + /** + * @var int[][] Map from "{$node->getType()}->{$subNode}" to ['left' => $l, 'right' => $r], + * where $l and $r specify the token type that needs to be stripped when removing + * this node. + */ + protected $removalMap; + /** + * @var mixed[] Map from "{$node->getType()}->{$subNode}" to [$find, $beforeToken, $extraLeft, $extraRight]. + * $find is an optional token after which the insertion occurs. $extraLeft/Right + * are optionally added before/after the main insertions. + */ + protected $insertionMap; + /** + * @var string[] Map From "{$node->getType()}->{$subNode}" to string that should be inserted + * between elements of this list subnode. + */ + protected $listInsertionMap; + protected $emptyListInsertionMap; + /** @var int[] Map from "{$node->getType()}->{$subNode}" to token before which the modifiers + * should be reprinted. */ + protected $modifierChangeMap; + /** + * Creates a pretty printer instance using the given options. + * + * Supported options: + * * bool $shortArraySyntax = false: Whether to use [] instead of array() as the default array + * syntax, if the node does not specify a format. + * + * @param array $options Dictionary of formatting options + */ + public function __construct(array $options = []) + { + $this->docStringEndToken = '_DOC_STRING_END_' . \mt_rand(); + $defaultOptions = ['shortArraySyntax' => \false]; + $this->options = $options + $defaultOptions; + } + /** + * Reset pretty printing state. + */ + protected function resetState() + { + $this->indentLevel = 0; + $this->nl = "\n"; + $this->origTokens = null; + } + /** + * Set indentation level + * + * @param int $level Level in number of spaces + */ + protected function setIndentLevel($level) + { + if (!\is_int($level)) { + if (!(\is_bool($level) || \is_numeric($level))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($level) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($level) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $level = (int) $level; + } + } + $this->indentLevel = $level; + $this->nl = "\n" . \str_repeat(' ', $level); + } + /** + * Increase indentation level. + */ + protected function indent() + { + $this->indentLevel += 4; + $this->nl .= ' '; + } + /** + * Decrease indentation level. + */ + protected function outdent() + { + \assert($this->indentLevel >= 4); + $this->indentLevel -= 4; + $this->nl = "\n" . \str_repeat(' ', $this->indentLevel); + } + /** + * Pretty prints an array of statements. + * + * @param Node[] $stmts Array of statements + * + * @return string Pretty printed statements + */ + public function prettyPrint(array $stmts) + { + $this->resetState(); + $this->preprocessNodes($stmts); + $phabelReturn = \ltrim($this->handleMagicTokens($this->pStmts($stmts, \false))); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Pretty prints an expression. + * + * @param Expr $node Expression node + * + * @return string Pretty printed node + */ + public function prettyPrintExpr(Expr $node) + { + $this->resetState(); + $phabelReturn = $this->handleMagicTokens($this->p($node)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Pretty prints a file of statements (includes the opening prettyPrint($stmts); + if ($stmts[0] instanceof Stmt\InlineHTML) { + $p = \preg_replace('/^<\\?php\\s+\\?>\\n?/', '', $p); + } + if ($stmts[\count($stmts) - 1] instanceof Stmt\InlineHTML) { + $p = \preg_replace('/<\\?php$/', '', \rtrim($p)); + } + $phabelReturn = $p; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Preprocesses the top-level nodes to initialize pretty printer state. + * + * @param Node[] $nodes Array of nodes + */ + protected function preprocessNodes(array $nodes) + { + /* We can use semicolon-namespaces unless there is a global namespace declaration */ + $this->canUseSemicolonNamespaces = \true; + foreach ($nodes as $node) { + if ($node instanceof Stmt\Namespace_ && null === $node->name) { + $this->canUseSemicolonNamespaces = \false; + break; + } + } + } + /** + * Handles (and removes) no-indent and doc-string-end tokens. + * + * @param string $str + * @return string + */ + protected function handleMagicTokens($str) + { + if (!\is_string($str)) { + if (!(\is_string($str) || \is_object($str) && \method_exists($str, '__toString') || (\is_bool($str) || \is_numeric($str)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($str) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($str) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $str = (string) $str; + } + } + // Replace doc-string-end tokens with nothing or a newline + $str = \str_replace($this->docStringEndToken . ";\n", ";\n", $str); + $str = \str_replace($this->docStringEndToken, "\n", $str); + $phabelReturn = $str; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Pretty prints an array of nodes (statements) and indents them optionally. + * + * @param Node[] $nodes Array of nodes + * @param bool $indent Whether to indent the printed nodes + * + * @return string Pretty printed statements + */ + protected function pStmts(array $nodes, $indent = \true) + { + if (!\is_bool($indent)) { + if (!(\is_bool($indent) || \is_numeric($indent) || \is_string($indent))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($indent) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($indent) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $indent = (bool) $indent; + } + } + if ($indent) { + $this->indent(); + } + $result = ''; + foreach ($nodes as $node) { + $comments = $node->getComments(); + if ($comments) { + $result .= $this->nl . $this->pComments($comments); + if ($node instanceof Stmt\Nop) { + continue; + } + } + $result .= $this->nl . $this->p($node); + } + if ($indent) { + $this->outdent(); + } + $phabelReturn = $result; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Pretty-print an infix operation while taking precedence into account. + * + * @param string $class Node class of operator + * @param Node $leftNode Left-hand side node + * @param string $operatorString String representation of the operator + * @param Node $rightNode Right-hand side node + * + * @return string Pretty printed infix operation + */ + protected function pInfixOp($class, Node $leftNode, $operatorString, Node $rightNode) + { + if (!\is_string($class)) { + if (!(\is_string($class) || \is_object($class) && \method_exists($class, '__toString') || (\is_bool($class) || \is_numeric($class)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($class) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($class) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $class = (string) $class; + } + } + if (!\is_string($operatorString)) { + if (!(\is_string($operatorString) || \is_object($operatorString) && \method_exists($operatorString, '__toString') || (\is_bool($operatorString) || \is_numeric($operatorString)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($operatorString) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($operatorString) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $operatorString = (string) $operatorString; + } + } + list($precedence, $associativity) = $this->precedenceMap[$class]; + $phabelReturn = $this->pPrec($leftNode, $precedence, $associativity, -1) . $operatorString . $this->pPrec($rightNode, $precedence, $associativity, 1); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Pretty-print a prefix operation while taking precedence into account. + * + * @param string $class Node class of operator + * @param string $operatorString String representation of the operator + * @param Node $node Node + * + * @return string Pretty printed prefix operation + */ + protected function pPrefixOp($class, $operatorString, Node $node) + { + if (!\is_string($class)) { + if (!(\is_string($class) || \is_object($class) && \method_exists($class, '__toString') || (\is_bool($class) || \is_numeric($class)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($class) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($class) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $class = (string) $class; + } + } + if (!\is_string($operatorString)) { + if (!(\is_string($operatorString) || \is_object($operatorString) && \method_exists($operatorString, '__toString') || (\is_bool($operatorString) || \is_numeric($operatorString)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($operatorString) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($operatorString) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $operatorString = (string) $operatorString; + } + } + list($precedence, $associativity) = $this->precedenceMap[$class]; + $phabelReturn = $operatorString . $this->pPrec($node, $precedence, $associativity, 1); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Pretty-print a postfix operation while taking precedence into account. + * + * @param string $class Node class of operator + * @param string $operatorString String representation of the operator + * @param Node $node Node + * + * @return string Pretty printed postfix operation + */ + protected function pPostfixOp($class, Node $node, $operatorString) + { + if (!\is_string($class)) { + if (!(\is_string($class) || \is_object($class) && \method_exists($class, '__toString') || (\is_bool($class) || \is_numeric($class)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($class) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($class) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $class = (string) $class; + } + } + if (!\is_string($operatorString)) { + if (!(\is_string($operatorString) || \is_object($operatorString) && \method_exists($operatorString, '__toString') || (\is_bool($operatorString) || \is_numeric($operatorString)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($operatorString) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($operatorString) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $operatorString = (string) $operatorString; + } + } + list($precedence, $associativity) = $this->precedenceMap[$class]; + $phabelReturn = $this->pPrec($node, $precedence, $associativity, -1) . $operatorString; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Prints an expression node with the least amount of parentheses necessary to preserve the meaning. + * + * @param Node $node Node to pretty print + * @param int $parentPrecedence Precedence of the parent operator + * @param int $parentAssociativity Associativity of parent operator + * (-1 is left, 0 is nonassoc, 1 is right) + * @param int $childPosition Position of the node relative to the operator + * (-1 is left, 1 is right) + * + * @return string The pretty printed node + */ + protected function pPrec(Node $node, $parentPrecedence, $parentAssociativity, $childPosition) + { + if (!\is_int($parentPrecedence)) { + if (!(\is_bool($parentPrecedence) || \is_numeric($parentPrecedence))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($parentPrecedence) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($parentPrecedence) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $parentPrecedence = (int) $parentPrecedence; + } + } + if (!\is_int($parentAssociativity)) { + if (!(\is_bool($parentAssociativity) || \is_numeric($parentAssociativity))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($parentAssociativity) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($parentAssociativity) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $parentAssociativity = (int) $parentAssociativity; + } + } + if (!\is_int($childPosition)) { + if (!(\is_bool($childPosition) || \is_numeric($childPosition))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($childPosition) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($childPosition) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $childPosition = (int) $childPosition; + } + } + $class = \get_class($node); + if (isset($this->precedenceMap[$class])) { + $childPrecedence = $this->precedenceMap[$class][0]; + if ($childPrecedence > $parentPrecedence || $parentPrecedence === $childPrecedence && $parentAssociativity !== $childPosition) { + $phabelReturn = '(' . $this->p($node) . ')'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + } + $phabelReturn = $this->p($node); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Pretty prints an array of nodes and implodes the printed values. + * + * @param Node[] $nodes Array of Nodes to be printed + * @param string $glue Character to implode with + * + * @return string Imploded pretty printed nodes + */ + protected function pImplode(array $nodes, $glue = '') + { + if (!\is_string($glue)) { + if (!(\is_string($glue) || \is_object($glue) && \method_exists($glue, '__toString') || (\is_bool($glue) || \is_numeric($glue)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($glue) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($glue) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $glue = (string) $glue; + } + } + $pNodes = []; + foreach ($nodes as $node) { + if (null === $node) { + $pNodes[] = ''; + } else { + $pNodes[] = $this->p($node); + } + } + $phabelReturn = \implode($glue, $pNodes); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Pretty prints an array of nodes and implodes the printed values with commas. + * + * @param Node[] $nodes Array of Nodes to be printed + * + * @return string Comma separated pretty printed nodes + */ + protected function pCommaSeparated(array $nodes) + { + $phabelReturn = $this->pImplode($nodes, ', '); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Pretty prints a comma-separated list of nodes in multiline style, including comments. + * + * The result includes a leading newline and one level of indentation (same as pStmts). + * + * @param Node[] $nodes Array of Nodes to be printed + * @param bool $trailingComma Whether to use a trailing comma + * + * @return string Comma separated pretty printed nodes in multiline style + */ + protected function pCommaSeparatedMultiline(array $nodes, $trailingComma) + { + if (!\is_bool($trailingComma)) { + if (!(\is_bool($trailingComma) || \is_numeric($trailingComma) || \is_string($trailingComma))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($trailingComma) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($trailingComma) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $trailingComma = (bool) $trailingComma; + } + } + $this->indent(); + $result = ''; + $lastIdx = \count($nodes) - 1; + foreach ($nodes as $idx => $node) { + if ($node !== null) { + $comments = $node->getComments(); + if ($comments) { + $result .= $this->nl . $this->pComments($comments); + } + $result .= $this->nl . $this->p($node); + } else { + $result .= $this->nl; + } + if ($trailingComma || $idx !== $lastIdx) { + $result .= ','; + } + } + $this->outdent(); + $phabelReturn = $result; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Prints reformatted text of the passed comments. + * + * @param Comment[] $comments List of comments + * + * @return string Reformatted text of comments + */ + protected function pComments(array $comments) + { + $formattedComments = []; + foreach ($comments as $comment) { + $formattedComments[] = \str_replace("\n", $this->nl, $comment->getReformattedText()); + } + $phabelReturn = \implode($this->nl, $formattedComments); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Perform a format-preserving pretty print of an AST. + * + * The format preservation is best effort. For some changes to the AST the formatting will not + * be preserved (at least not locally). + * + * In order to use this method a number of prerequisites must be satisfied: + * * The startTokenPos and endTokenPos attributes in the lexer must be enabled. + * * The CloningVisitor must be run on the AST prior to modification. + * * The original tokens must be provided, using the getTokens() method on the lexer. + * + * @param Node[] $stmts Modified AST with links to original AST + * @param Node[] $origStmts Original AST with token offset information + * @param array $origTokens Tokens of the original code + * + * @return string + */ + public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens) + { + $this->initializeNodeListDiffer(); + $this->initializeLabelCharMap(); + $this->initializeFixupMap(); + $this->initializeRemovalMap(); + $this->initializeInsertionMap(); + $this->initializeListInsertionMap(); + $this->initializeEmptyListInsertionMap(); + $this->initializeModifierChangeMap(); + $this->resetState(); + $this->origTokens = new TokenStream($origTokens); + $this->preprocessNodes($stmts); + $pos = 0; + $result = $this->pArray($stmts, $origStmts, $pos, 0, 'File', 'stmts', null); + if (null !== $result) { + $result .= $this->origTokens->getTokenCode($pos, \count($origTokens), 0); + } else { + // Fallback + // TODO Add pStmts($stmts, \false); + } + $phabelReturn = \ltrim($this->handleMagicTokens($result)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + protected function pFallback(Node $node) + { + return $this->{'p' . $node->getType()}($node); + } + /** + * Pretty prints a node. + * + * This method also handles formatting preservation for nodes. + * + * @param Node $node Node to be pretty printed + * @param bool $parentFormatPreserved Whether parent node has preserved formatting + * + * @return string Pretty printed node + */ + protected function p(Node $node, $parentFormatPreserved = \false) + { + // No orig tokens means this is a normal pretty print without preservation of formatting + if (!$this->origTokens) { + $phabelReturn = $this->{'p' . $node->getType()}($node); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** @var Node $origNode */ + $origNode = $node->getAttribute('origNode'); + if (null === $origNode) { + $phabelReturn = $this->pFallback($node); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $class = \get_class($node); + \assert($class === \get_class($origNode)); + $startPos = $origNode->getStartTokenPos(); + $endPos = $origNode->getEndTokenPos(); + \assert($startPos >= 0 && $endPos >= 0); + $fallbackNode = $node; + if ($node instanceof Expr\New_ && $node->class instanceof Stmt\Class_) { + // Normalize node structure of anonymous classes + $node = PrintableNewAnonClassNode::fromNewNode($node); + $origNode = PrintableNewAnonClassNode::fromNewNode($origNode); + } + // InlineHTML node does not contain closing and opening PHP tags. If the parent formatting + // is not preserved, then we need to use the fallback code to make sure the tags are + // printed. + if ($node instanceof Stmt\InlineHTML && !$parentFormatPreserved) { + $phabelReturn = $this->pFallback($fallbackNode); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $indentAdjustment = $this->indentLevel - $this->origTokens->getIndentationBefore($startPos); + $type = $node->getType(); + $fixupInfo = isset($this->fixupMap[$class]) ? $this->fixupMap[$class] : null; + $result = ''; + $pos = $startPos; + foreach ($node->getSubNodeNames() as $subNodeName) { + $subNode = $node->{$subNodeName}; + $origSubNode = $origNode->{$subNodeName}; + if (!$subNode instanceof Node && $subNode !== null || !$origSubNode instanceof Node && $origSubNode !== null) { + if ($subNode === $origSubNode) { + // Unchanged, can reuse old code + continue; + } + if (\is_array($subNode) && \is_array($origSubNode)) { + // Array subnode changed, we might be able to reconstruct it + $listResult = $this->pArray($subNode, $origSubNode, $pos, $indentAdjustment, $type, $subNodeName, isset($fixupInfo[$subNodeName]) ? $fixupInfo[$subNodeName] : null); + if (null === $listResult) { + $phabelReturn = $this->pFallback($fallbackNode); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $result .= $listResult; + continue; + } + if (\is_int($subNode) && \is_int($origSubNode)) { + // Check if this is a modifier change + $key = $type . '->' . $subNodeName; + if (!isset($this->modifierChangeMap[$key])) { + $phabelReturn = $this->pFallback($fallbackNode); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $findToken = $this->modifierChangeMap[$key]; + $result .= $this->pModifiers($subNode); + $pos = $this->origTokens->findRight($pos, $findToken); + continue; + } + $phabelReturn = $this->pFallback($fallbackNode); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + // If a non-node, non-array subnode changed, we don't be able to do a partial + // reconstructions, as we don't have enough offset information. Pretty print the + // whole node instead. + return $phabelReturn; + } + $extraLeft = ''; + $extraRight = ''; + if ($origSubNode !== null) { + $subStartPos = $origSubNode->getStartTokenPos(); + $subEndPos = $origSubNode->getEndTokenPos(); + \assert($subStartPos >= 0 && $subEndPos >= 0); + } else { + if ($subNode === null) { + // Both null, nothing to do + continue; + } + // A node has been inserted, check if we have insertion information for it + $key = $type . '->' . $subNodeName; + if (!isset($this->insertionMap[$key])) { + $phabelReturn = $this->pFallback($fallbackNode); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + list($findToken, $beforeToken, $extraLeft, $extraRight) = $this->insertionMap[$key]; + if (null !== $findToken) { + $subStartPos = $this->origTokens->findRight($pos, $findToken) + (int) (!$beforeToken); + } else { + $subStartPos = $pos; + } + if (null === $extraLeft && null !== $extraRight) { + // If inserting on the right only, skipping whitespace looks better + $subStartPos = $this->origTokens->skipRightWhitespace($subStartPos); + } + $subEndPos = $subStartPos - 1; + } + if (null === $subNode) { + // A node has been removed, check if we have removal information for it + $key = $type . '->' . $subNodeName; + if (!isset($this->removalMap[$key])) { + $phabelReturn = $this->pFallback($fallbackNode); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + // Adjust positions to account for additional tokens that must be skipped + $removalInfo = $this->removalMap[$key]; + if (isset($removalInfo['left'])) { + $subStartPos = $this->origTokens->skipLeft($subStartPos - 1, $removalInfo['left']) + 1; + } + if (isset($removalInfo['right'])) { + $subEndPos = $this->origTokens->skipRight($subEndPos + 1, $removalInfo['right']) - 1; + } + } + $result .= $this->origTokens->getTokenCode($pos, $subStartPos, $indentAdjustment); + if (null !== $subNode) { + $result .= $extraLeft; + $origIndentLevel = $this->indentLevel; + $this->setIndentLevel($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment); + // If it's the same node that was previously in this position, it certainly doesn't + // need fixup. It's important to check this here, because our fixup checks are more + // conservative than strictly necessary. + if (isset($fixupInfo[$subNodeName]) && $subNode->getAttribute('origNode') !== $origSubNode) { + $fixup = $fixupInfo[$subNodeName]; + $res = $this->pFixup($fixup, $subNode, $class, $subStartPos, $subEndPos); + } else { + $res = $this->p($subNode, \true); + } + $this->safeAppend($result, $res); + $this->setIndentLevel($origIndentLevel); + $result .= $extraRight; + } + $pos = $subEndPos + 1; + } + $result .= $this->origTokens->getTokenCode($pos, $endPos + 1, $indentAdjustment); + $phabelReturn = $result; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Perform a format-preserving pretty print of an array. + * + * @param array $nodes New nodes + * @param array $origNodes Original nodes + * @param int $pos Current token position (updated by reference) + * @param int $indentAdjustment Adjustment for indentation + * @param string $parentNodeType Type of the containing node. + * @param string $subNodeName Name of array subnode. + * @param null|int $fixup Fixup information for array item nodes + * + * @return null|string Result of pretty print or null if cannot preserve formatting + */ + protected function pArray(array $nodes, array $origNodes, &$pos, $indentAdjustment, $parentNodeType, $subNodeName, $fixup) + { + if (!\is_int($pos)) { + if (!(\is_bool($pos) || \is_numeric($pos))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($pos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($pos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $pos = (int) $pos; + } + } + if (!\is_int($indentAdjustment)) { + if (!(\is_bool($indentAdjustment) || \is_numeric($indentAdjustment))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($indentAdjustment) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($indentAdjustment) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $indentAdjustment = (int) $indentAdjustment; + } + } + if (!\is_string($parentNodeType)) { + if (!(\is_string($parentNodeType) || \is_object($parentNodeType) && \method_exists($parentNodeType, '__toString') || (\is_bool($parentNodeType) || \is_numeric($parentNodeType)))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($parentNodeType) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($parentNodeType) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $parentNodeType = (string) $parentNodeType; + } + } + if (!\is_string($subNodeName)) { + if (!(\is_string($subNodeName) || \is_object($subNodeName) && \method_exists($subNodeName, '__toString') || (\is_bool($subNodeName) || \is_numeric($subNodeName)))) { + throw new \TypeError(__METHOD__ . '(): Argument #6 ($subNodeName) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($subNodeName) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $subNodeName = (string) $subNodeName; + } + } + $diff = $this->nodeListDiffer->diffWithReplacements($origNodes, $nodes); + $mapKey = $parentNodeType . '->' . $subNodeName; + $insertStr = isset($this->listInsertionMap[$mapKey]) ? $this->listInsertionMap[$mapKey] : null; + $isStmtList = $subNodeName === 'stmts'; + $beforeFirstKeepOrReplace = \true; + $skipRemovedNode = \false; + $delayedAdd = []; + $lastElemIndentLevel = $this->indentLevel; + $insertNewline = \false; + if ($insertStr === "\n") { + $insertStr = ''; + $insertNewline = \true; + } + if ($isStmtList && \count($origNodes) === 1 && \count($nodes) !== 1) { + $startPos = $origNodes[0]->getStartTokenPos(); + $endPos = $origNodes[0]->getEndTokenPos(); + \assert($startPos >= 0 && $endPos >= 0); + if (!$this->origTokens->haveBraces($startPos, $endPos)) { + // This was a single statement without braces, but either additional statements + // have been added, or the single statement has been removed. This requires the + // addition of braces. For now fall back. + // TODO: Try to preserve formatting + return null; + } + } + $result = ''; + foreach ($diff as $i => $diffElem) { + $diffType = $diffElem->type; + /** @var Node|null $arrItem */ + $arrItem = $diffElem->new; + /** @var Node|null $origArrItem */ + $origArrItem = $diffElem->old; + if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) { + $beforeFirstKeepOrReplace = \false; + if ($origArrItem === null || $arrItem === null) { + // We can only handle the case where both are null + if ($origArrItem === $arrItem) { + continue; + } + return null; + } + if (!$arrItem instanceof Node || !$origArrItem instanceof Node) { + // We can only deal with nodes. This can occur for Names, which use string arrays. + return null; + } + $itemStartPos = $origArrItem->getStartTokenPos(); + $itemEndPos = $origArrItem->getEndTokenPos(); + \assert($itemStartPos >= 0 && $itemEndPos >= 0 && $itemStartPos >= $pos); + $origIndentLevel = $this->indentLevel; + $lastElemIndentLevel = $this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment; + $this->setIndentLevel($lastElemIndentLevel); + $comments = $arrItem->getComments(); + $origComments = $origArrItem->getComments(); + $commentStartPos = $origComments ? $origComments[0]->getStartTokenPos() : $itemStartPos; + \assert($commentStartPos >= 0); + if ($commentStartPos < $pos) { + // Comments may be assigned to multiple nodes if they start at the same position. + // Make sure we don't try to print them multiple times. + $commentStartPos = $itemStartPos; + } + if ($skipRemovedNode) { + if ($isStmtList && $this->origTokens->haveBracesInRange($pos, $itemStartPos)) { + // We'd remove the brace of a code block. + // TODO: Preserve formatting. + $this->setIndentLevel($origIndentLevel); + return null; + } + } else { + $result .= $this->origTokens->getTokenCode($pos, $commentStartPos, $indentAdjustment); + } + if (!empty($delayedAdd)) { + /** @var Node $delayedAddNode */ + foreach ($delayedAdd as $delayedAddNode) { + if ($insertNewline) { + $delayedAddComments = $delayedAddNode->getComments(); + if ($delayedAddComments) { + $result .= $this->pComments($delayedAddComments) . $this->nl; + } + } + $this->safeAppend($result, $this->p($delayedAddNode, \true)); + if ($insertNewline) { + $result .= $insertStr . $this->nl; + } else { + $result .= $insertStr; + } + } + $delayedAdd = []; + } + if ($comments !== $origComments) { + if ($comments) { + $result .= $this->pComments($comments) . $this->nl; + } + } else { + $result .= $this->origTokens->getTokenCode($commentStartPos, $itemStartPos, $indentAdjustment); + } + // If we had to remove anything, we have done so now. + $skipRemovedNode = \false; + } elseif ($diffType === DiffElem::TYPE_ADD) { + if (null === $insertStr) { + // We don't have insertion information for this list type + return null; + } + if ($insertStr === ', ' && $this->isMultiline($origNodes)) { + $insertStr = ','; + $insertNewline = \true; + } + if ($beforeFirstKeepOrReplace) { + // Will be inserted at the next "replace" or "keep" element + $delayedAdd[] = $arrItem; + continue; + } + $itemStartPos = $pos; + $itemEndPos = $pos - 1; + $origIndentLevel = $this->indentLevel; + $this->setIndentLevel($lastElemIndentLevel); + if ($insertNewline) { + $comments = $arrItem->getComments(); + if ($comments) { + $result .= $this->nl . $this->pComments($comments); + } + $result .= $insertStr . $this->nl; + } else { + $result .= $insertStr; + } + } elseif ($diffType === DiffElem::TYPE_REMOVE) { + if (!$origArrItem instanceof Node) { + // We only support removal for nodes + return null; + } + $itemStartPos = $origArrItem->getStartTokenPos(); + $itemEndPos = $origArrItem->getEndTokenPos(); + \assert($itemStartPos >= 0 && $itemEndPos >= 0); + // Consider comments part of the node. + $origComments = $origArrItem->getComments(); + if ($origComments) { + $itemStartPos = $origComments[0]->getStartTokenPos(); + } + if ($i === 0) { + // If we're removing from the start, keep the tokens before the node and drop those after it, + // instead of the other way around. + $result .= $this->origTokens->getTokenCode($pos, $itemStartPos, $indentAdjustment); + $skipRemovedNode = \true; + } else { + if ($isStmtList && $this->origTokens->haveBracesInRange($pos, $itemStartPos)) { + // We'd remove the brace of a code block. + // TODO: Preserve formatting. + return null; + } + } + $pos = $itemEndPos + 1; + continue; + } else { + throw new \Exception("Shouldn't happen"); + } + if (null !== $fixup && $arrItem->getAttribute('origNode') !== $origArrItem) { + $res = $this->pFixup($fixup, $arrItem, null, $itemStartPos, $itemEndPos); + } else { + $res = $this->p($arrItem, \true); + } + $this->safeAppend($result, $res); + $this->setIndentLevel($origIndentLevel); + $pos = $itemEndPos + 1; + } + if ($skipRemovedNode) { + // TODO: Support removing single node. + return null; + } + if (!empty($delayedAdd)) { + if (!isset($this->emptyListInsertionMap[$mapKey])) { + return null; + } + list($findToken, $extraLeft, $extraRight) = $this->emptyListInsertionMap[$mapKey]; + if (null !== $findToken) { + $insertPos = $this->origTokens->findRight($pos, $findToken) + 1; + $result .= $this->origTokens->getTokenCode($pos, $insertPos, $indentAdjustment); + $pos = $insertPos; + } + $first = \true; + $result .= $extraLeft; + foreach ($delayedAdd as $delayedAddNode) { + if (!$first) { + $result .= $insertStr; + } + $result .= $this->p($delayedAddNode, \true); + $first = \false; + } + $result .= $extraRight; + } + return $result; + } + /** + * Print node with fixups. + * + * Fixups here refer to the addition of extra parentheses, braces or other characters, that + * are required to preserve program semantics in a certain context (e.g. to maintain precedence + * or because only certain expressions are allowed in certain places). + * + * @param int $fixup Fixup type + * @param Node $subNode Subnode to print + * @param string|null $parentClass Class of parent node + * @param int $subStartPos Original start pos of subnode + * @param int $subEndPos Original end pos of subnode + * + * @return string Result of fixed-up print of subnode + */ + protected function pFixup($fixup, Node $subNode, $parentClass, $subStartPos, $subEndPos) + { + if (!\is_int($fixup)) { + if (!(\is_bool($fixup) || \is_numeric($fixup))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($fixup) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($fixup) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $fixup = (int) $fixup; + } + } + if (!\is_int($subStartPos)) { + if (!(\is_bool($subStartPos) || \is_numeric($subStartPos))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($subStartPos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($subStartPos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $subStartPos = (int) $subStartPos; + } + } + if (!\is_int($subEndPos)) { + if (!(\is_bool($subEndPos) || \is_numeric($subEndPos))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($subEndPos) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($subEndPos) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $subEndPos = (int) $subEndPos; + } + } + switch ($fixup) { + case self::FIXUP_PREC_LEFT: + case self::FIXUP_PREC_RIGHT: + if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) { + list($precedence, $associativity) = $this->precedenceMap[$parentClass]; + $phabelReturn = $this->pPrec($subNode, $precedence, $associativity, $fixup === self::FIXUP_PREC_LEFT ? -1 : 1); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + break; + case self::FIXUP_CALL_LHS: + if ($this->callLhsRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { + $phabelReturn = '(' . $this->p($subNode) . ')'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + break; + case self::FIXUP_DEREF_LHS: + if ($this->dereferenceLhsRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { + $phabelReturn = '(' . $this->p($subNode) . ')'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + break; + case self::FIXUP_BRACED_NAME: + case self::FIXUP_VAR_BRACED_NAME: + if ($subNode instanceof Expr && !$this->origTokens->haveBraces($subStartPos, $subEndPos)) { + $phabelReturn = ($fixup === self::FIXUP_VAR_BRACED_NAME ? '$' : '') . '{' . $this->p($subNode) . '}'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + break; + case self::FIXUP_ENCAPSED: + if (!$subNode instanceof Scalar\EncapsedStringPart && !$this->origTokens->haveBraces($subStartPos, $subEndPos)) { + $phabelReturn = '{' . $this->p($subNode) . '}'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + break; + default: + throw new \Exception('Cannot happen'); + } + $phabelReturn = $this->p($subNode); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + // Nothing special to do + return $phabelReturn; + } + /** + * Appends to a string, ensuring whitespace between label characters. + * + * Example: "echo" and "$x" result in "echo$x", but "echo" and "x" result in "echo x". + * Without safeAppend the result would be "echox", which does not preserve semantics. + * + * @param string $str + * @param string $append + */ + protected function safeAppend(&$str, $append) + { + if (!\is_string($str)) { + if (!(\is_string($str) || \is_object($str) && \method_exists($str, '__toString') || (\is_bool($str) || \is_numeric($str)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($str) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($str) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $str = (string) $str; + } + } + if (!\is_string($append)) { + if (!(\is_string($append) || \is_object($append) && \method_exists($append, '__toString') || (\is_bool($append) || \is_numeric($append)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($append) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($append) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $append = (string) $append; + } + } + if ($str === "") { + $str = $append; + return; + } + if ($append === "") { + return; + } + if (!$this->labelCharMap[$append[0]] || !$this->labelCharMap[$str[\strlen($str) - 1]]) { + $str .= $append; + } else { + $str .= " " . $append; + } + } + /** + * Determines whether the LHS of a call must be wrapped in parenthesis. + * + * @param Node $node LHS of a call + * + * @return bool Whether parentheses are required + */ + protected function callLhsRequiresParens(Node $node) + { + $phabelReturn = !($node instanceof Node\Name || $node instanceof Expr\Variable || $node instanceof Expr\ArrayDimFetch || $node instanceof Expr\FuncCall || $node instanceof Expr\MethodCall || $node instanceof Expr\NullsafeMethodCall || $node instanceof Expr\StaticCall || $node instanceof Expr\Array_); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Determines whether the LHS of a dereferencing operation must be wrapped in parenthesis. + * + * @param Node $node LHS of dereferencing operation + * + * @return bool Whether parentheses are required + */ + protected function dereferenceLhsRequiresParens(Node $node) + { + $phabelReturn = !($node instanceof Expr\Variable || $node instanceof Node\Name || $node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch || $node instanceof Expr\NullsafePropertyFetch || $node instanceof Expr\StaticPropertyFetch || $node instanceof Expr\FuncCall || $node instanceof Expr\MethodCall || $node instanceof Expr\NullsafeMethodCall || $node instanceof Expr\StaticCall || $node instanceof Expr\Array_ || $node instanceof Scalar\String_ || $node instanceof Expr\ConstFetch || $node instanceof Expr\ClassConstFetch); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Print modifiers, including trailing whitespace. + * + * @param int $modifiers Modifier mask to print + * + * @return string Printed modifiers + */ + protected function pModifiers($modifiers) + { + if (!\is_int($modifiers)) { + if (!(\is_bool($modifiers) || \is_numeric($modifiers))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($modifiers) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($modifiers) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $modifiers = (int) $modifiers; + } + } + return ($modifiers & Stmt\Class_::MODIFIER_PUBLIC ? 'public ' : '') . ($modifiers & Stmt\Class_::MODIFIER_PROTECTED ? 'protected ' : '') . ($modifiers & Stmt\Class_::MODIFIER_PRIVATE ? 'private ' : '') . ($modifiers & Stmt\Class_::MODIFIER_STATIC ? 'static ' : '') . ($modifiers & Stmt\Class_::MODIFIER_ABSTRACT ? 'abstract ' : '') . ($modifiers & Stmt\Class_::MODIFIER_FINAL ? 'final ' : ''); + } + /** + * Determine whether a list of nodes uses multiline formatting. + * + * @param (Node|null)[] $nodes Node list + * + * @return bool Whether multiline formatting is used + */ + protected function isMultiline(array $nodes) + { + if (\count($nodes) < 2) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $pos = -1; + foreach ($nodes as $node) { + if (null === $node) { + continue; + } + $endPos = $node->getEndTokenPos() + 1; + if ($pos >= 0) { + $text = $this->origTokens->getTokenCode($pos, $endPos, 0); + if (\false === \strpos($text, "\n")) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + // We require that a newline is present between *every* item. If the formatting + // is inconsistent, with only some items having newlines, we don't consider it + // as multiline + return $phabelReturn; + } + } + $pos = $endPos; + } + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Lazily initializes label char map. + * + * The label char map determines whether a certain character may occur in a label. + */ + protected function initializeLabelCharMap() + { + if ($this->labelCharMap) { + return; + } + $this->labelCharMap = []; + for ($i = 0; $i < 256; $i++) { + // Since PHP 7.1 The lower range is 0x80. However, we also want to support code for + // older versions. + $this->labelCharMap[\chr($i)] = $i >= 0x7f || \ctype_alnum($i); + } + } + /** + * Lazily initializes node list differ. + * + * The node list differ is used to determine differences between two array subnodes. + */ + protected function initializeNodeListDiffer() + { + if ($this->nodeListDiffer) { + return; + } + $this->nodeListDiffer = new Internal\Differ(function ($a, $b) { + if ($a instanceof Node && $b instanceof Node) { + return $a === $b->getAttribute('origNode'); + } + // Can happen for array destructuring + return $a === null && $b === null; + }); + } + /** + * Lazily initializes fixup map. + * + * The fixup map is used to determine whether a certain subnode of a certain node may require + * some kind of "fixup" operation, e.g. the addition of parenthesis or braces. + */ + protected function initializeFixupMap() + { + if ($this->fixupMap) { + return; + } + $this->fixupMap = [ + Expr\PreInc::class => ['var' => self::FIXUP_PREC_RIGHT], + Expr\PreDec::class => ['var' => self::FIXUP_PREC_RIGHT], + Expr\PostInc::class => ['var' => self::FIXUP_PREC_LEFT], + Expr\PostDec::class => ['var' => self::FIXUP_PREC_LEFT], + Expr\Instanceof_::class => ['expr' => self::FIXUP_PREC_LEFT, 'class' => self::FIXUP_PREC_RIGHT], + Expr\Ternary::class => ['cond' => self::FIXUP_PREC_LEFT, 'else' => self::FIXUP_PREC_RIGHT], + Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS], + Expr\StaticCall::class => ['class' => self::FIXUP_DEREF_LHS], + Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS], + Expr\ClassConstFetch::class => ['var' => self::FIXUP_DEREF_LHS], + Expr\New_::class => ['class' => self::FIXUP_DEREF_LHS], + // TODO: FIXUP_NEW_VARIABLE + Expr\MethodCall::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], + Expr\NullsafeMethodCall::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], + Expr\StaticPropertyFetch::class => ['class' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_VAR_BRACED_NAME], + Expr\PropertyFetch::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], + Expr\NullsafePropertyFetch::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], + Scalar\Encapsed::class => ['parts' => self::FIXUP_ENCAPSED], + ]; + $binaryOps = [BinaryOp\Pow::class, BinaryOp\Mul::class, BinaryOp\Div::class, BinaryOp\Mod::class, BinaryOp\Plus::class, BinaryOp\Minus::class, BinaryOp\Concat::class, BinaryOp\ShiftLeft::class, BinaryOp\ShiftRight::class, BinaryOp\Smaller::class, BinaryOp\SmallerOrEqual::class, BinaryOp\Greater::class, BinaryOp\GreaterOrEqual::class, BinaryOp\Equal::class, BinaryOp\NotEqual::class, BinaryOp\Identical::class, BinaryOp\NotIdentical::class, BinaryOp\Spaceship::class, BinaryOp\BitwiseAnd::class, BinaryOp\BitwiseXor::class, BinaryOp\BitwiseOr::class, BinaryOp\BooleanAnd::class, BinaryOp\BooleanOr::class, BinaryOp\Coalesce::class, BinaryOp\LogicalAnd::class, BinaryOp\LogicalXor::class, BinaryOp\LogicalOr::class]; + foreach ($binaryOps as $binaryOp) { + $this->fixupMap[$binaryOp] = ['left' => self::FIXUP_PREC_LEFT, 'right' => self::FIXUP_PREC_RIGHT]; + } + $assignOps = [Expr\Assign::class, Expr\AssignRef::class, AssignOp\Plus::class, AssignOp\Minus::class, AssignOp\Mul::class, AssignOp\Div::class, AssignOp\Concat::class, AssignOp\Mod::class, AssignOp\BitwiseAnd::class, AssignOp\BitwiseOr::class, AssignOp\BitwiseXor::class, AssignOp\ShiftLeft::class, AssignOp\ShiftRight::class, AssignOp\Pow::class, AssignOp\Coalesce::class]; + foreach ($assignOps as $assignOp) { + $this->fixupMap[$assignOp] = ['var' => self::FIXUP_PREC_LEFT, 'expr' => self::FIXUP_PREC_RIGHT]; + } + $prefixOps = [Expr\BitwiseNot::class, Expr\BooleanNot::class, Expr\UnaryPlus::class, Expr\UnaryMinus::class, Cast\Int_::class, Cast\Double::class, Cast\String_::class, Cast\Array_::class, Cast\Object_::class, Cast\Bool_::class, Cast\Unset_::class, Expr\ErrorSuppress::class, Expr\YieldFrom::class, Expr\Print_::class, Expr\Include_::class]; + foreach ($prefixOps as $prefixOp) { + $this->fixupMap[$prefixOp] = ['expr' => self::FIXUP_PREC_RIGHT]; + } + } + /** + * Lazily initializes the removal map. + * + * The removal map is used to determine which additional tokens should be returned when a + * certain node is replaced by null. + */ + protected function initializeRemovalMap() + { + if ($this->removalMap) { + return; + } + $stripBoth = ['left' => \T_WHITESPACE, 'right' => \T_WHITESPACE]; + $stripLeft = ['left' => \T_WHITESPACE]; + $stripRight = ['right' => \T_WHITESPACE]; + $stripDoubleArrow = ['right' => \T_DOUBLE_ARROW]; + $stripColon = ['left' => ':']; + $stripEquals = ['left' => '=']; + $this->removalMap = ['Expr_ArrayDimFetch->dim' => $stripBoth, 'Expr_ArrayItem->key' => $stripDoubleArrow, 'Expr_ArrowFunction->returnType' => $stripColon, 'Expr_Closure->returnType' => $stripColon, 'Expr_Exit->expr' => $stripBoth, 'Expr_Ternary->if' => $stripBoth, 'Expr_Yield->key' => $stripDoubleArrow, 'Expr_Yield->value' => $stripBoth, 'Param->type' => $stripRight, 'Param->default' => $stripEquals, 'Stmt_Break->num' => $stripBoth, 'Stmt_Catch->var' => $stripLeft, 'Stmt_ClassMethod->returnType' => $stripColon, 'Stmt_Class->extends' => ['left' => \T_EXTENDS], 'Expr_PrintableNewAnonClass->extends' => ['left' => \T_EXTENDS], 'Stmt_Continue->num' => $stripBoth, 'Stmt_Foreach->keyVar' => $stripDoubleArrow, 'Stmt_Function->returnType' => $stripColon, 'Stmt_If->else' => $stripLeft, 'Stmt_Namespace->name' => $stripLeft, 'Stmt_Property->type' => $stripRight, 'Stmt_PropertyProperty->default' => $stripEquals, 'Stmt_Return->expr' => $stripBoth, 'Stmt_StaticVar->default' => $stripEquals, 'Stmt_TraitUseAdaptation_Alias->newName' => $stripLeft, 'Stmt_TryCatch->finally' => $stripLeft]; + } + protected function initializeInsertionMap() + { + if ($this->insertionMap) { + return; + } + // TODO: "yield" where both key and value are inserted doesn't work + // [$find, $beforeToken, $extraLeft, $extraRight] + $this->insertionMap = [ + 'Expr_ArrayDimFetch->dim' => ['[', \false, null, null], + 'Expr_ArrayItem->key' => [null, \false, null, ' => '], + 'Expr_ArrowFunction->returnType' => [')', \false, ' : ', null], + 'Expr_Closure->returnType' => [')', \false, ' : ', null], + 'Expr_Ternary->if' => ['?', \false, ' ', ' '], + 'Expr_Yield->key' => [\T_YIELD, \false, null, ' => '], + 'Expr_Yield->value' => [\T_YIELD, \false, ' ', null], + 'Param->type' => [null, \false, null, ' '], + 'Param->default' => [null, \false, ' = ', null], + 'Stmt_Break->num' => [\T_BREAK, \false, ' ', null], + 'Stmt_Catch->var' => [null, \false, ' ', null], + 'Stmt_ClassMethod->returnType' => [')', \false, ' : ', null], + 'Stmt_Class->extends' => [null, \false, ' extends ', null], + 'Expr_PrintableNewAnonClass->extends' => [null, ' extends ', null], + 'Stmt_Continue->num' => [\T_CONTINUE, \false, ' ', null], + 'Stmt_Foreach->keyVar' => [\T_AS, \false, null, ' => '], + 'Stmt_Function->returnType' => [')', \false, ' : ', null], + 'Stmt_If->else' => [null, \false, ' ', null], + 'Stmt_Namespace->name' => [\T_NAMESPACE, \false, ' ', null], + 'Stmt_Property->type' => [\T_VARIABLE, \true, null, ' '], + 'Stmt_PropertyProperty->default' => [null, \false, ' = ', null], + 'Stmt_Return->expr' => [\T_RETURN, \false, ' ', null], + 'Stmt_StaticVar->default' => [null, \false, ' = ', null], + //'Stmt_TraitUseAdaptation_Alias->newName' => [T_AS, false, ' ', null], // TODO + 'Stmt_TryCatch->finally' => [null, \false, ' ', null], + ]; + } + protected function initializeListInsertionMap() + { + if ($this->listInsertionMap) { + return; + } + $this->listInsertionMap = [ + // special + //'Expr_ShellExec->parts' => '', // TODO These need to be treated more carefully + //'Scalar_Encapsed->parts' => '', + 'Stmt_Catch->types' => '|', + 'UnionType->types' => '|', + 'Stmt_If->elseifs' => ' ', + 'Stmt_TryCatch->catches' => ' ', + // comma-separated lists + 'Expr_Array->items' => ', ', + 'Expr_ArrowFunction->params' => ', ', + 'Expr_Closure->params' => ', ', + 'Expr_Closure->uses' => ', ', + 'Expr_FuncCall->args' => ', ', + 'Expr_Isset->vars' => ', ', + 'Expr_List->items' => ', ', + 'Expr_MethodCall->args' => ', ', + 'Expr_NullsafeMethodCall->args' => ', ', + 'Expr_New->args' => ', ', + 'Expr_PrintableNewAnonClass->args' => ', ', + 'Expr_StaticCall->args' => ', ', + 'Stmt_ClassConst->consts' => ', ', + 'Stmt_ClassMethod->params' => ', ', + 'Stmt_Class->implements' => ', ', + 'Expr_PrintableNewAnonClass->implements' => ', ', + 'Stmt_Const->consts' => ', ', + 'Stmt_Declare->declares' => ', ', + 'Stmt_Echo->exprs' => ', ', + 'Stmt_For->init' => ', ', + 'Stmt_For->cond' => ', ', + 'Stmt_For->loop' => ', ', + 'Stmt_Function->params' => ', ', + 'Stmt_Global->vars' => ', ', + 'Stmt_GroupUse->uses' => ', ', + 'Stmt_Interface->extends' => ', ', + 'Stmt_Match->arms' => ', ', + 'Stmt_Property->props' => ', ', + 'Stmt_StaticVar->vars' => ', ', + 'Stmt_TraitUse->traits' => ', ', + 'Stmt_TraitUseAdaptation_Precedence->insteadof' => ', ', + 'Stmt_Unset->vars' => ', ', + 'Stmt_Use->uses' => ', ', + 'MatchArm->conds' => ', ', + 'AttributeGroup->attrs' => ', ', + // statement lists + 'Expr_Closure->stmts' => "\n", + 'Stmt_Case->stmts' => "\n", + 'Stmt_Catch->stmts' => "\n", + 'Stmt_Class->stmts' => "\n", + 'Expr_PrintableNewAnonClass->stmts' => "\n", + 'Stmt_Interface->stmts' => "\n", + 'Stmt_Trait->stmts' => "\n", + 'Stmt_ClassMethod->stmts' => "\n", + 'Stmt_Declare->stmts' => "\n", + 'Stmt_Do->stmts' => "\n", + 'Stmt_ElseIf->stmts' => "\n", + 'Stmt_Else->stmts' => "\n", + 'Stmt_Finally->stmts' => "\n", + 'Stmt_Foreach->stmts' => "\n", + 'Stmt_For->stmts' => "\n", + 'Stmt_Function->stmts' => "\n", + 'Stmt_If->stmts' => "\n", + 'Stmt_Namespace->stmts' => "\n", + 'Stmt_Class->attrGroups' => "\n", + 'Stmt_Interface->attrGroups' => "\n", + 'Stmt_Trait->attrGroups' => "\n", + 'Stmt_Function->attrGroups' => "\n", + 'Stmt_ClassMethod->attrGroups' => "\n", + 'Stmt_ClassConst->attrGroups' => "\n", + 'Stmt_Property->attrGroups' => "\n", + 'Expr_PrintableNewAnonClass->attrGroups' => ' ', + 'Expr_Closure->attrGroups' => ' ', + 'Expr_ArrowFunction->attrGroups' => ' ', + 'Param->attrGroups' => ' ', + 'Stmt_Switch->cases' => "\n", + 'Stmt_TraitUse->adaptations' => "\n", + 'Stmt_TryCatch->stmts' => "\n", + 'Stmt_While->stmts' => "\n", + // dummy for top-level context + 'File->stmts' => "\n", + ]; + } + protected function initializeEmptyListInsertionMap() + { + if ($this->emptyListInsertionMap) { + return; + } + // TODO Insertion into empty statement lists. + // [$find, $extraLeft, $extraRight] + $this->emptyListInsertionMap = ['Expr_ArrowFunction->params' => ['(', '', ''], 'Expr_Closure->uses' => [')', ' use(', ')'], 'Expr_Closure->params' => ['(', '', ''], 'Expr_FuncCall->args' => ['(', '', ''], 'Expr_MethodCall->args' => ['(', '', ''], 'Expr_NullsafeMethodCall->args' => ['(', '', ''], 'Expr_New->args' => ['(', '', ''], 'Expr_PrintableNewAnonClass->args' => ['(', '', ''], 'Expr_PrintableNewAnonClass->implements' => [null, ' implements ', ''], 'Expr_StaticCall->args' => ['(', '', ''], 'Stmt_Class->implements' => [null, ' implements ', ''], 'Stmt_ClassMethod->params' => ['(', '', ''], 'Stmt_Interface->extends' => [null, ' extends ', ''], 'Stmt_Function->params' => ['(', '', '']]; + } + protected function initializeModifierChangeMap() + { + if ($this->modifierChangeMap) { + return; + } + $this->modifierChangeMap = ['Stmt_ClassConst->flags' => \T_CONST, 'Stmt_ClassMethod->flags' => \T_FUNCTION, 'Stmt_Class->flags' => \T_CLASS, 'Stmt_Property->flags' => \T_VARIABLE, 'Param->flags' => \T_VARIABLE]; + // List of integer subnodes that are not modifiers: + // Expr_Include->type + // Stmt_GroupUse->type + // Stmt_Use->type + // Stmt_UseUse->type + } +} diff --git a/vendor-bundle/phabel/php-parser/tools/convertPhabel.php b/vendor-bundle/phabel/php-parser/tools/convertPhabel.php new file mode 100644 index 000000000..adf81d1a0 --- /dev/null +++ b/vendor-bundle/phabel/php-parser/tools/convertPhabel.php @@ -0,0 +1,70 @@ + ['target' => $target]], $dir, $dir, $coverage); + } + $str = (string) $target; + $packages["php"] = ">={$str[0]}.{$str[1]}"; + if (!empty($packages)) { + $cmd = "composer require "; + foreach ($packages as $package => $constraint) { + $cmd .= \escapeshellarg("{$package}:{$constraint}") . " "; + } + \passthru($cmd); + } + \passthru("composer cs-fix"); + if (!$dry) { + \passthru("git add -A"); + \passthru("git commit -m " . \escapeshellarg("phabel.io: transpile to {$target}")); + } + } + if (!$dry) { + \passthru("git push -f origin " . \escapeshellarg("phabel_tmp:{$branch}-{$target}")); + \passthru("git checkout " . \escapeshellarg($branch)); + \passthru("git branch -D phabel_tmp"); + } + \passthru("git reset --hard"); +} +\passthru("git stash pop"); diff --git a/vendor-bundle/psr/container/src/ContainerExceptionInterface.php b/vendor-bundle/psr/container/src/ContainerExceptionInterface.php new file mode 100644 index 000000000..5d90861f6 --- /dev/null +++ b/vendor-bundle/psr/container/src/ContainerExceptionInterface.php @@ -0,0 +1,10 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function alert($message, array $context = array()) + { + $this->log(LogLevel::ALERT, $message, $context); + } + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function critical($message, array $context = array()) + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function error($message, array $context = array()) + { + $this->log(LogLevel::ERROR, $message, $context); + } + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function warning($message, array $context = array()) + { + $this->log(LogLevel::WARNING, $message, $context); + } + /** + * Normal but significant events. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function notice($message, array $context = array()) + { + $this->log(LogLevel::NOTICE, $message, $context); + } + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function info($message, array $context = array()) + { + $this->log(LogLevel::INFO, $message, $context); + } + /** + * Detailed debug information. + * + * @param string $message + * @param mixed[] $context + * + * @return void + */ + public function debug($message, array $context = array()) + { + $this->log(LogLevel::DEBUG, $message, $context); + } +} diff --git a/vendor-bundle/psr/log/Psr/Log/InvalidArgumentException.php b/vendor-bundle/psr/log/Psr/Log/InvalidArgumentException.php new file mode 100644 index 000000000..9adb99943 --- /dev/null +++ b/vendor-bundle/psr/log/Psr/Log/InvalidArgumentException.php @@ -0,0 +1,7 @@ +logger = $logger; + } +} diff --git a/vendor-bundle/psr/log/Psr/Log/LoggerInterface.php b/vendor-bundle/psr/log/Psr/Log/LoggerInterface.php new file mode 100644 index 000000000..b997fcbb3 --- /dev/null +++ b/vendor-bundle/psr/log/Psr/Log/LoggerInterface.php @@ -0,0 +1,117 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function alert($message, array $context = array()) + { + $this->log(LogLevel::ALERT, $message, $context); + } + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function critical($message, array $context = array()) + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function error($message, array $context = array()) + { + $this->log(LogLevel::ERROR, $message, $context); + } + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function warning($message, array $context = array()) + { + $this->log(LogLevel::WARNING, $message, $context); + } + /** + * Normal but significant events. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function notice($message, array $context = array()) + { + $this->log(LogLevel::NOTICE, $message, $context); + } + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function info($message, array $context = array()) + { + $this->log(LogLevel::INFO, $message, $context); + } + /** + * Detailed debug information. + * + * @param string $message + * @param array $context + * + * @return void + */ + public function debug($message, array $context = array()) + { + $this->log(LogLevel::DEBUG, $message, $context); + } + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * + * @return void + * + * @throws \Psr\Log\InvalidArgumentException + */ + public abstract function log($level, $message, array $context = array()); +} diff --git a/vendor-bundle/psr/log/Psr/Log/NullLogger.php b/vendor-bundle/psr/log/Psr/Log/NullLogger.php new file mode 100644 index 000000000..570c0aa64 --- /dev/null +++ b/vendor-bundle/psr/log/Psr/Log/NullLogger.php @@ -0,0 +1,30 @@ +logger) { }` + * blocks. + */ +class NullLogger extends AbstractLogger +{ + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * @param string $message + * @param array $context + * + * @return void + * + * @throws \Psr\Log\InvalidArgumentException + */ + public function log($level, $message, array $context = array()) + { + // noop + } +} diff --git a/vendor-bundle/psr/log/Psr/Log/Test/DummyTest.php b/vendor-bundle/psr/log/Psr/Log/Test/DummyTest.php new file mode 100644 index 000000000..91578f9ca --- /dev/null +++ b/vendor-bundle/psr/log/Psr/Log/Test/DummyTest.php @@ -0,0 +1,18 @@ + ". + * + * Example ->error('Foo') would yield "error Foo". + * + * @return string[] + */ + public abstract function getLogs(); + public function testImplements() + { + $this->assertInstanceOf('Phabel\\Psr\\Log\\LoggerInterface', $this->getLogger()); + } + /** + * @dataProvider provideLevelsAndMessages + */ + public function testLogsAtAllLevels($level, $message) + { + $logger = $this->getLogger(); + $logger->{$level}($message, array('user' => 'Bob')); + $logger->log($level, $message, array('user' => 'Bob')); + $expected = array($level . ' message of level ' . $level . ' with context: Bob', $level . ' message of level ' . $level . ' with context: Bob'); + $this->assertEquals($expected, $this->getLogs()); + } + public function provideLevelsAndMessages() + { + return array(LogLevel::EMERGENCY => array(LogLevel::EMERGENCY, 'message of level emergency with context: {user}'), LogLevel::ALERT => array(LogLevel::ALERT, 'message of level alert with context: {user}'), LogLevel::CRITICAL => array(LogLevel::CRITICAL, 'message of level critical with context: {user}'), LogLevel::ERROR => array(LogLevel::ERROR, 'message of level error with context: {user}'), LogLevel::WARNING => array(LogLevel::WARNING, 'message of level warning with context: {user}'), LogLevel::NOTICE => array(LogLevel::NOTICE, 'message of level notice with context: {user}'), LogLevel::INFO => array(LogLevel::INFO, 'message of level info with context: {user}'), LogLevel::DEBUG => array(LogLevel::DEBUG, 'message of level debug with context: {user}')); + } + /** + * @expectedException \Psr\Log\InvalidArgumentException + */ + public function testThrowsOnInvalidLevel() + { + $logger = $this->getLogger(); + $logger->log('invalid level', 'Foo'); + } + public function testContextReplacement() + { + $logger = $this->getLogger(); + $logger->info('{Message {nothing} {user} {foo.bar} a}', array('user' => 'Bob', 'foo.bar' => 'Bar')); + $expected = array('info {Message {nothing} Bob Bar a}'); + $this->assertEquals($expected, $this->getLogs()); + } + public function testObjectCastToString() + { + if (\method_exists($this, 'createPartialMock')) { + $dummy = $this->createPartialMock('Phabel\\Psr\\Log\\Test\\DummyTest', array('__toString')); + } else { + $dummy = $this->getMock('Phabel\\Psr\\Log\\Test\\DummyTest', array('__toString')); + } + $dummy->expects($this->once())->method('__toString')->will($this->returnValue('DUMMY')); + $this->getLogger()->warning($dummy); + $expected = array('warning DUMMY'); + $this->assertEquals($expected, $this->getLogs()); + } + public function testContextCanContainAnything() + { + $closed = \fopen('php://memory', 'r'); + \fclose($closed); + $context = array('bool' => \true, 'null' => null, 'string' => 'Foo', 'int' => 0, 'float' => 0.5, 'nested' => array('with object' => new DummyTest()), 'object' => new \DateTime(), 'resource' => \fopen('php://memory', 'r'), 'closed' => $closed); + $this->getLogger()->warning('Crazy context data', $context); + $expected = array('warning Crazy context data'); + $this->assertEquals($expected, $this->getLogs()); + } + public function testContextExceptionKeyCanBeExceptionOrOtherValues() + { + $logger = $this->getLogger(); + $logger->warning('Random message', array('exception' => 'oops')); + $logger->critical('Uncaught Exception!', array('exception' => new \LogicException('Fail'))); + $expected = array('warning Random message', 'critical Uncaught Exception!'); + $this->assertEquals($expected, $this->getLogs()); + } +} diff --git a/vendor-bundle/psr/log/Psr/Log/Test/TestLogger.php b/vendor-bundle/psr/log/Psr/Log/Test/TestLogger.php new file mode 100644 index 000000000..5d0944215 --- /dev/null +++ b/vendor-bundle/psr/log/Psr/Log/Test/TestLogger.php @@ -0,0 +1,132 @@ + $level, 'message' => $message, 'context' => $context]; + $this->recordsByLevel[$record['level']][] = $record; + $this->records[] = $record; + } + public function hasRecords($level) + { + return isset($this->recordsByLevel[$level]); + } + public function hasRecord($record, $level) + { + if (\is_string($record)) { + $record = ['message' => $record]; + } + return $this->hasRecordThatPasses(function ($rec) use($record) { + if ($rec['message'] !== $record['message']) { + return \false; + } + if (isset($record['context']) && $rec['context'] !== $record['context']) { + return \false; + } + return \true; + }, $level); + } + public function hasRecordThatContains($message, $level) + { + return $this->hasRecordThatPasses(function ($rec) use($message) { + return \strpos($rec['message'], $message) !== \false; + }, $level); + } + public function hasRecordThatMatches($regex, $level) + { + return $this->hasRecordThatPasses(function ($rec) use($regex) { + return \preg_match($regex, $rec['message']) > 0; + }, $level); + } + public function hasRecordThatPasses(callable $predicate, $level) + { + if (!isset($this->recordsByLevel[$level])) { + return \false; + } + foreach ($this->recordsByLevel[$level] as $i => $rec) { + if (\call_user_func($predicate, $rec, $i)) { + return \true; + } + } + return \false; + } + public function __call($method, $args) + { + if (\preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { + $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3]; + $level = \strtolower($matches[2]); + if (\method_exists($this, $genericMethod)) { + $args[] = $level; + return \call_user_func_array([$this, $genericMethod], $args); + } + } + throw new \BadMethodCallException('Call to undefined method ' . \get_class($this) . '::' . $method . '()'); + } + public function reset() + { + $this->records = []; + $this->recordsByLevel = []; + } +} diff --git a/vendor-bundle/ralouphie/getallheaders/src/getallheaders.php b/vendor-bundle/ralouphie/getallheaders/src/getallheaders.php new file mode 100644 index 000000000..31f03505a --- /dev/null +++ b/vendor-bundle/ralouphie/getallheaders/src/getallheaders.php @@ -0,0 +1,38 @@ + 'Content-Type', 'CONTENT_LENGTH' => 'Content-Length', 'CONTENT_MD5' => 'Content-Md5'); + foreach ($_SERVER as $key => $value) { + if (\substr($key, 0, 5) === 'HTTP_') { + $key = \substr($key, 5); + if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) { + $key = \str_replace(' ', '-', \ucwords(\strtolower(\str_replace('_', ' ', $key)))); + $headers[$key] = $value; + } + } elseif (isset($copy_server[$key])) { + $headers[$copy_server[$key]] = $value; + } + } + if (!isset($headers['Authorization'])) { + if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { + $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; + } elseif (isset($_SERVER['PHP_AUTH_USER'])) { + $basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : ''; + $headers['Authorization'] = 'Basic ' . \base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass); + } elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) { + $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST']; + } + } + return $headers; + } +} diff --git a/vendor-bundle/symfony/console/Application.php b/vendor-bundle/symfony/console/Application.php new file mode 100644 index 000000000..705954f5c --- /dev/null +++ b/vendor-bundle/symfony/console/Application.php @@ -0,0 +1,1262 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console; + +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Command\HelpCommand; +use Phabel\Symfony\Component\Console\Command\LazyCommand; +use Phabel\Symfony\Component\Console\Command\ListCommand; +use Phabel\Symfony\Component\Console\Command\SignalableCommandInterface; +use Phabel\Symfony\Component\Console\CommandLoader\CommandLoaderInterface; +use Phabel\Symfony\Component\Console\Event\ConsoleCommandEvent; +use Phabel\Symfony\Component\Console\Event\ConsoleErrorEvent; +use Phabel\Symfony\Component\Console\Event\ConsoleSignalEvent; +use Phabel\Symfony\Component\Console\Event\ConsoleTerminateEvent; +use Phabel\Symfony\Component\Console\Exception\CommandNotFoundException; +use Phabel\Symfony\Component\Console\Exception\ExceptionInterface; +use Phabel\Symfony\Component\Console\Exception\LogicException; +use Phabel\Symfony\Component\Console\Exception\NamespaceNotFoundException; +use Phabel\Symfony\Component\Console\Exception\RuntimeException; +use Phabel\Symfony\Component\Console\Formatter\OutputFormatter; +use Phabel\Symfony\Component\Console\Helper\DebugFormatterHelper; +use Phabel\Symfony\Component\Console\Helper\FormatterHelper; +use Phabel\Symfony\Component\Console\Helper\Helper; +use Phabel\Symfony\Component\Console\Helper\HelperSet; +use Phabel\Symfony\Component\Console\Helper\ProcessHelper; +use Phabel\Symfony\Component\Console\Helper\QuestionHelper; +use Phabel\Symfony\Component\Console\Input\ArgvInput; +use Phabel\Symfony\Component\Console\Input\ArrayInput; +use Phabel\Symfony\Component\Console\Input\InputArgument; +use Phabel\Symfony\Component\Console\Input\InputAwareInterface; +use Phabel\Symfony\Component\Console\Input\InputDefinition; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Input\InputOption; +use Phabel\Symfony\Component\Console\Output\ConsoleOutput; +use Phabel\Symfony\Component\Console\Output\ConsoleOutputInterface; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +use Phabel\Symfony\Component\Console\SignalRegistry\SignalRegistry; +use Phabel\Symfony\Component\Console\Style\SymfonyStyle; +use Phabel\Symfony\Component\ErrorHandler\ErrorHandler; +use Phabel\Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Phabel\Symfony\Contracts\Service\ResetInterface; +/** + * An Application is the container for a collection of commands. + * + * It is the main entry point of a Console application. + * + * This class is optimized for a standard CLI environment. + * + * Usage: + * + * $app = new Application('myapp', '1.0 (stable)'); + * $app->add(new SimpleCommand()); + * $app->run(); + * + * @author Fabien Potencier + */ +class Application implements ResetInterface +{ + private $commands = []; + private $wantHelps = \false; + private $runningCommand; + private $name; + private $version; + private $commandLoader; + private $catchExceptions = \true; + private $autoExit = \true; + private $definition; + private $helperSet; + private $dispatcher; + private $terminal; + private $defaultCommand; + private $singleCommand = \false; + private $initialized; + private $signalRegistry; + private $signalsToDispatchEvent = []; + public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN') + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_string($version)) { + if (!(\is_string($version) || \is_object($version) && \method_exists($version, '__toString') || (\is_bool($version) || \is_numeric($version)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($version) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($version) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $version = (string) $version; + } + } + $this->name = $name; + $this->version = $version; + $this->terminal = new Terminal(); + $this->defaultCommand = 'list'; + if (\defined('SIGINT') && SignalRegistry::isSupported()) { + $this->signalRegistry = new SignalRegistry(); + $this->signalsToDispatchEvent = [\SIGINT, \SIGTERM, \SIGUSR1, \SIGUSR2]; + } + } + /** + * @final + */ + public function setDispatcher(EventDispatcherInterface $dispatcher) + { + $this->dispatcher = $dispatcher; + } + public function setCommandLoader(CommandLoaderInterface $commandLoader) + { + $this->commandLoader = $commandLoader; + } + public function getSignalRegistry() + { + if (!$this->signalRegistry) { + throw new RuntimeException('Signals are not supported. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); + } + $phabelReturn = $this->signalRegistry; + if (!$phabelReturn instanceof SignalRegistry) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type SignalRegistry, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function setSignalsToDispatchEvent(...$signalsToDispatchEvent) + { + foreach ($signalsToDispatchEvent as $phabelVariadicIndex => $phabelVariadic) { + if (!\is_int($phabelVariadic)) { + if (!(\is_bool($phabelVariadic) || \is_numeric($phabelVariadic))) { + throw new \TypeError(__METHOD__ . '(): Argument #' . (1 + $phabelVariadicIndex) . ' must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signalsToDispatchEvent) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelVariadic = (int) $phabelVariadic; + } + } + } + $this->signalsToDispatchEvent = $signalsToDispatchEvent; + } + /** + * Runs the current application. + * + * @return int 0 if everything went fine, or an error code + * + * @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}. + */ + public function run(InputInterface $input = null, OutputInterface $output = null) + { + if (\function_exists('putenv')) { + @\putenv('LINES=' . $this->terminal->getHeight()); + @\putenv('COLUMNS=' . $this->terminal->getWidth()); + } + if (null === $input) { + $input = new ArgvInput(); + } + if (null === $output) { + $output = new ConsoleOutput(); + } + $renderException = function (\Throwable $e) use($output) { + if ($output instanceof ConsoleOutputInterface) { + $this->renderThrowable($e, $output->getErrorOutput()); + } else { + $this->renderThrowable($e, $output); + } + }; + if ($phpHandler = \set_exception_handler($renderException)) { + \restore_exception_handler(); + if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) { + $errorHandler = \true; + } elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) { + $phpHandler[0]->setExceptionHandler($errorHandler); + } + } + $this->configureIO($input, $output); + try { + $exitCode = $this->doRun($input, $output); + } catch (\Exception $e) { + if (!$this->catchExceptions) { + throw $e; + } + $renderException($e); + $exitCode = $e->getCode(); + if (\is_numeric($exitCode)) { + $exitCode = (int) $exitCode; + if (0 === $exitCode) { + $exitCode = 1; + } + } else { + $exitCode = 1; + } + } finally { + // if the exception handler changed, keep it + // otherwise, unregister $renderException + if (!$phpHandler) { + if (\set_exception_handler($renderException) === $renderException) { + \restore_exception_handler(); + } + \restore_exception_handler(); + } elseif (!$errorHandler) { + $finalHandler = $phpHandler[0]->setExceptionHandler(null); + if ($finalHandler !== $renderException) { + $phpHandler[0]->setExceptionHandler($finalHandler); + } + } + } + if ($this->autoExit) { + if ($exitCode > 255) { + $exitCode = 255; + } + exit($exitCode); + } + return $exitCode; + } + /** + * Runs the current application. + * + * @return int 0 if everything went fine, or an error code + */ + public function doRun(InputInterface $input, OutputInterface $output) + { + if (\true === $input->hasParameterOption(['--version', '-V'], \true)) { + $output->writeln($this->getLongVersion()); + return 0; + } + try { + // Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument. + $input->bind($this->getDefinition()); + } catch (ExceptionInterface $e) { + // Errors must be ignored, full binding/validation happens later when the command is known. + } + $name = $this->getCommandName($input); + if (\true === $input->hasParameterOption(['--help', '-h'], \true)) { + if (!$name) { + $name = 'help'; + $input = new ArrayInput(['command_name' => $this->defaultCommand]); + } else { + $this->wantHelps = \true; + } + } + if (!$name) { + $name = $this->defaultCommand; + $definition = $this->getDefinition(); + $definition->setArguments(\array_merge($definition->getArguments(), ['command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name)])); + } + try { + $this->runningCommand = null; + // the command name MUST be the first element of the input + $command = $this->find($name); + } catch (\Exception $e) { + if (!($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) || 1 !== \count($alternatives = $e->getAlternatives()) || !$input->isInteractive()) { + if (null !== $this->dispatcher) { + $event = new ConsoleErrorEvent($input, $output, $e); + $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); + if (0 === $event->getExitCode()) { + return 0; + } + $e = $event->getError(); + } + throw $e; + } + $alternative = $alternatives[0]; + $style = new SymfonyStyle($input, $output); + $style->block(\sprintf("\nCommand \"%s\" is not defined.\n", $name), null, 'error'); + if (!$style->confirm(\sprintf('Do you want to run "%s" instead? ', $alternative), \false)) { + if (null !== $this->dispatcher) { + $event = new ConsoleErrorEvent($input, $output, $e); + $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); + return $event->getExitCode(); + } + return 1; + } + $command = $this->find($alternative); + } catch (\Error $e) { + if (!($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException) || 1 !== \count($alternatives = $e->getAlternatives()) || !$input->isInteractive()) { + if (null !== $this->dispatcher) { + $event = new ConsoleErrorEvent($input, $output, $e); + $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); + if (0 === $event->getExitCode()) { + return 0; + } + $e = $event->getError(); + } + throw $e; + } + $alternative = $alternatives[0]; + $style = new SymfonyStyle($input, $output); + $style->block(\sprintf("\nCommand \"%s\" is not defined.\n", $name), null, 'error'); + if (!$style->confirm(\sprintf('Do you want to run "%s" instead? ', $alternative), \false)) { + if (null !== $this->dispatcher) { + $event = new ConsoleErrorEvent($input, $output, $e); + $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); + return $event->getExitCode(); + } + return 1; + } + $command = $this->find($alternative); + } + if ($command instanceof LazyCommand) { + $command = $command->getCommand(); + } + $this->runningCommand = $command; + $exitCode = $this->doRunCommand($command, $input, $output); + $this->runningCommand = null; + return $exitCode; + } + /** + * {@inheritdoc} + */ + public function reset() + { + } + public function setHelperSet(HelperSet $helperSet) + { + $this->helperSet = $helperSet; + } + /** + * Get the helper set associated with the command. + * + * @return HelperSet The HelperSet instance associated with this command + */ + public function getHelperSet() + { + if (!$this->helperSet) { + $this->helperSet = $this->getDefaultHelperSet(); + } + return $this->helperSet; + } + public function setDefinition(InputDefinition $definition) + { + $this->definition = $definition; + } + /** + * Gets the InputDefinition related to this Application. + * + * @return InputDefinition The InputDefinition instance + */ + public function getDefinition() + { + if (!$this->definition) { + $this->definition = $this->getDefaultInputDefinition(); + } + if ($this->singleCommand) { + $inputDefinition = $this->definition; + $inputDefinition->setArguments(); + return $inputDefinition; + } + return $this->definition; + } + /** + * Gets the help message. + * + * @return string A help message + */ + public function getHelp() + { + return $this->getLongVersion(); + } + /** + * Gets whether to catch exceptions or not during commands execution. + * + * @return bool Whether to catch exceptions or not during commands execution + */ + public function areExceptionsCaught() + { + return $this->catchExceptions; + } + /** + * Sets whether to catch exceptions or not during commands execution. + */ + public function setCatchExceptions($boolean) + { + if (!\is_bool($boolean)) { + if (!(\is_bool($boolean) || \is_numeric($boolean) || \is_string($boolean))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($boolean) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($boolean) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $boolean = (bool) $boolean; + } + } + $this->catchExceptions = $boolean; + } + /** + * Gets whether to automatically exit after a command execution or not. + * + * @return bool Whether to automatically exit after a command execution or not + */ + public function isAutoExitEnabled() + { + return $this->autoExit; + } + /** + * Sets whether to automatically exit after a command execution or not. + */ + public function setAutoExit($boolean) + { + if (!\is_bool($boolean)) { + if (!(\is_bool($boolean) || \is_numeric($boolean) || \is_string($boolean))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($boolean) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($boolean) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $boolean = (bool) $boolean; + } + } + $this->autoExit = $boolean; + } + /** + * Gets the name of the application. + * + * @return string The application name + */ + public function getName() + { + return $this->name; + } + /** + * Sets the application name. + **/ + public function setName($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $this->name = $name; + } + /** + * Gets the application version. + * + * @return string The application version + */ + public function getVersion() + { + return $this->version; + } + /** + * Sets the application version. + */ + public function setVersion($version) + { + if (!\is_string($version)) { + if (!(\is_string($version) || \is_object($version) && \method_exists($version, '__toString') || (\is_bool($version) || \is_numeric($version)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($version) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($version) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $version = (string) $version; + } + } + $this->version = $version; + } + /** + * Returns the long version of the application. + * + * @return string The long application version + */ + public function getLongVersion() + { + if ('UNKNOWN' !== $this->getName()) { + if ('UNKNOWN' !== $this->getVersion()) { + return \sprintf('%s %s', $this->getName(), $this->getVersion()); + } + return $this->getName(); + } + return 'Console Tool'; + } + /** + * Registers a new command. + * + * @return Command The newly created command + */ + public function register($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + return $this->add(new Command($name)); + } + /** + * Adds an array of command objects. + * + * If a Command is not enabled it will not be added. + * + * @param Command[] $commands An array of commands + */ + public function addCommands(array $commands) + { + foreach ($commands as $command) { + $this->add($command); + } + } + /** + * Adds a command object. + * + * If a command with the same name already exists, it will be overridden. + * If the command is not enabled it will not be added. + * + * @return Command|null The registered command if enabled or null + */ + public function add(Command $command) + { + $this->init(); + $command->setApplication($this); + if (!$command->isEnabled()) { + $command->setApplication(null); + return null; + } + if (!$command instanceof LazyCommand) { + // Will throw if the command is not correctly initialized. + $command->getDefinition(); + } + if (!$command->getName()) { + throw new LogicException(\sprintf('The command defined in "%s" cannot have an empty name.', \get_debug_type($command))); + } + $this->commands[$command->getName()] = $command; + foreach ($command->getAliases() as $alias) { + $this->commands[$alias] = $command; + } + return $command; + } + /** + * Returns a registered command by name or alias. + * + * @return Command A Command object + * + * @throws CommandNotFoundException When given command name does not exist + */ + public function get($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $this->init(); + if (!$this->has($name)) { + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); + } + // When the command has a different name than the one used at the command loader level + if (!isset($this->commands[$name])) { + throw new CommandNotFoundException(\sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); + } + $command = $this->commands[$name]; + if ($this->wantHelps) { + $this->wantHelps = \false; + $helpCommand = $this->get('help'); + $helpCommand->setCommand($command); + return $helpCommand; + } + return $command; + } + /** + * Returns true if the command exists, false otherwise. + * + * @return bool true if the command exists, false otherwise + */ + public function has($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $this->init(); + return isset($this->commands[$name]) || $this->commandLoader && $this->commandLoader->has($name) && $this->add($this->commandLoader->get($name)); + } + /** + * Returns an array of all unique namespaces used by currently registered commands. + * + * It does not return the global namespace which always exists. + * + * @return string[] An array of namespaces + */ + public function getNamespaces() + { + $namespaces = []; + foreach ($this->all() as $command) { + if ($command->isHidden()) { + continue; + } + $namespaces = \array_merge($namespaces, $this->extractAllNamespaces($command->getName())); + foreach ($command->getAliases() as $alias) { + $namespaces = \array_merge($namespaces, $this->extractAllNamespaces($alias)); + } + } + return \array_values(\array_unique(\array_filter($namespaces))); + } + /** + * Finds a registered namespace by a name or an abbreviation. + * + * @return string A registered namespace + * + * @throws NamespaceNotFoundException When namespace is incorrect or ambiguous + */ + public function findNamespace($namespace) + { + if (!\is_string($namespace)) { + if (!(\is_string($namespace) || \is_object($namespace) && \method_exists($namespace, '__toString') || (\is_bool($namespace) || \is_numeric($namespace)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($namespace) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($namespace) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $namespace = (string) $namespace; + } + } + $allNamespaces = $this->getNamespaces(); + $expr = \implode('[^:]*:', \array_map('preg_quote', \explode(':', $namespace))) . '[^:]*'; + $namespaces = \preg_grep('{^' . $expr . '}', $allNamespaces); + if (empty($namespaces)) { + $message = \sprintf('There are no commands defined in the "%s" namespace.', $namespace); + if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { + if (1 == \count($alternatives)) { + $message .= "\n\nDid you mean this?\n "; + } else { + $message .= "\n\nDid you mean one of these?\n "; + } + $message .= \implode("\n ", $alternatives); + } + throw new NamespaceNotFoundException($message, $alternatives); + } + $exact = \in_array($namespace, $namespaces, \true); + if (\count($namespaces) > 1 && !$exact) { + throw new NamespaceNotFoundException(\sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(\array_values($namespaces))), \array_values($namespaces)); + } + return $exact ? $namespace : \reset($namespaces); + } + /** + * Finds a command by name or alias. + * + * Contrary to get, this command tries to find the best + * match if you give it an abbreviation of a name or alias. + * + * @return Command A Command instance + * + * @throws CommandNotFoundException When command name is incorrect or ambiguous + */ + public function find($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $this->init(); + $aliases = []; + foreach ($this->commands as $command) { + foreach ($command->getAliases() as $alias) { + if (!$this->has($alias)) { + $this->commands[$alias] = $command; + } + } + } + if ($this->has($name)) { + return $this->get($name); + } + $allCommands = $this->commandLoader ? \array_merge($this->commandLoader->getNames(), \array_keys($this->commands)) : \array_keys($this->commands); + $expr = \implode('[^:]*:', \array_map('preg_quote', \explode(':', $name))) . '[^:]*'; + $commands = \preg_grep('{^' . $expr . '}', $allCommands); + if (empty($commands)) { + $commands = \preg_grep('{^' . $expr . '}i', $allCommands); + } + // if no commands matched or we just matched namespaces + if (empty($commands) || \count(\preg_grep('{^' . $expr . '$}i', $commands)) < 1) { + if (\false !== ($pos = \strrpos($name, ':'))) { + // check if a namespace exists and contains commands + $this->findNamespace(\substr($name, 0, $pos)); + } + $message = \sprintf('Command "%s" is not defined.', $name); + if ($alternatives = $this->findAlternatives($name, $allCommands)) { + // remove hidden commands + $alternatives = \array_filter($alternatives, function ($name) { + return !$this->get($name)->isHidden(); + }); + if (1 == \count($alternatives)) { + $message .= "\n\nDid you mean this?\n "; + } else { + $message .= "\n\nDid you mean one of these?\n "; + } + $message .= \implode("\n ", $alternatives); + } + throw new CommandNotFoundException($message, \array_values($alternatives)); + } + // filter out aliases for commands which are already on the list + if (\count($commands) > 1) { + $commandList = $this->commandLoader ? \array_merge(\array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands; + $commands = \array_unique(\array_filter($commands, function ($nameOrAlias) use(&$commandList, $commands, &$aliases) { + if (!$commandList[$nameOrAlias] instanceof Command) { + $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias); + } + $commandName = $commandList[$nameOrAlias]->getName(); + $aliases[$nameOrAlias] = $commandName; + return $commandName === $nameOrAlias || !\in_array($commandName, $commands); + })); + } + if (\count($commands) > 1) { + $usableWidth = $this->terminal->getWidth() - 10; + $abbrevs = \array_values($commands); + $maxLen = 0; + foreach ($abbrevs as $abbrev) { + $maxLen = \max(Helper::width($abbrev), $maxLen); + } + $abbrevs = \array_map(function ($cmd) use($commandList, $usableWidth, $maxLen, &$commands) { + if ($commandList[$cmd]->isHidden()) { + unset($commands[\array_search($cmd, $commands)]); + return \false; + } + $abbrev = \str_pad($cmd, $maxLen, ' ') . ' ' . $commandList[$cmd]->getDescription(); + return Helper::width($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3) . '...' : $abbrev; + }, \array_values($commands)); + if (\count($commands) > 1) { + $suggestions = $this->getAbbreviationSuggestions(\array_filter($abbrevs)); + throw new CommandNotFoundException(\sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), \array_values($commands)); + } + } + $command = $this->get(\reset($commands)); + if ($command->isHidden()) { + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); + } + return $command; + } + /** + * Gets the commands (registered in the given namespace if provided). + * + * The array keys are the full names and the values the command instances. + * + * @return Command[] An array of Command instances + */ + public function all($namespace = null) + { + if (!\is_null($namespace)) { + if (!\is_string($namespace)) { + if (!(\is_string($namespace) || \is_object($namespace) && \method_exists($namespace, '__toString') || (\is_bool($namespace) || \is_numeric($namespace)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($namespace) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($namespace) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $namespace = (string) $namespace; + } + } + } + $this->init(); + if (null === $namespace) { + if (!$this->commandLoader) { + return $this->commands; + } + $commands = $this->commands; + foreach ($this->commandLoader->getNames() as $name) { + if (!isset($commands[$name]) && $this->has($name)) { + $commands[$name] = $this->get($name); + } + } + return $commands; + } + $commands = []; + foreach ($this->commands as $name => $command) { + if ($namespace === $this->extractNamespace($name, \substr_count($namespace, ':') + 1)) { + $commands[$name] = $command; + } + } + if ($this->commandLoader) { + foreach ($this->commandLoader->getNames() as $name) { + if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, \substr_count($namespace, ':') + 1) && $this->has($name)) { + $commands[$name] = $this->get($name); + } + } + } + return $commands; + } + /** + * Returns an array of possible abbreviations given a set of names. + * + * @return string[][] An array of abbreviations + */ + public static function getAbbreviations(array $names) + { + $abbrevs = []; + foreach ($names as $name) { + for ($len = \strlen($name); $len > 0; --$len) { + $abbrev = \substr($name, 0, $len); + $abbrevs[$abbrev][] = $name; + } + } + return $abbrevs; + } + public function renderThrowable(\Throwable $e, OutputInterface $output) + { + $output->writeln('', OutputInterface::VERBOSITY_QUIET); + $this->doRenderThrowable($e, $output); + if (null !== $this->runningCommand) { + $output->writeln(\sprintf('%s', OutputFormatter::escape(\sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); + $output->writeln('', OutputInterface::VERBOSITY_QUIET); + } + } + protected function doRenderThrowable(\Throwable $e, OutputInterface $output) + { + do { + $message = \trim($e->getMessage()); + if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $class = \get_debug_type($e); + $title = \sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' (' . $code . ')' : ''); + $len = Helper::width($title); + } else { + $len = 0; + } + if (\str_contains($message, "@anonymous\x00")) { + $message = \preg_replace_callback('/[a-zA-Z_\\x7f-\\xff][\\\\a-zA-Z0-9_\\x7f-\\xff]*+@anonymous\\x00.*?\\.php(?:0x?|:[0-9]++\\$)[0-9a-fA-F]++/', function ($m) { + return \class_exists($m[0], \false) ? ((\get_parent_class($m[0]) ?: \key(\class_implements($m[0]))) ?: 'class') . '@anonymous' : $m[0]; + }, $message); + } + $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX; + $lines = []; + foreach ('' !== $message ? \preg_split('/\\r?\\n/', $message) : [] as $line) { + foreach ($this->splitStringByWidth($line, $width - 4) as $line) { + // pre-format lines to get the right string length + $lineLength = Helper::width($line) + 4; + $lines[] = [$line, $lineLength]; + $len = \max($lineLength, $len); + } + } + $messages = []; + if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $messages[] = \sprintf('%s', OutputFormatter::escape(\sprintf('In %s line %s:', \basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); + } + $messages[] = $emptyLine = \sprintf('%s', \str_repeat(' ', $len)); + if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $messages[] = \sprintf('%s%s', $title, \str_repeat(' ', \max(0, $len - Helper::width($title)))); + } + foreach ($lines as $line) { + $messages[] = \sprintf(' %s %s', OutputFormatter::escape($line[0]), \str_repeat(' ', $len - $line[1])); + } + $messages[] = $emptyLine; + $messages[] = ''; + $output->writeln($messages, OutputInterface::VERBOSITY_QUIET); + if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $output->writeln('Exception trace:', OutputInterface::VERBOSITY_QUIET); + // exception related properties + $trace = $e->getTrace(); + \array_unshift($trace, ['function' => '', 'file' => $e->getFile() ?: 'n/a', 'line' => $e->getLine() ?: 'n/a', 'args' => []]); + for ($i = 0, $count = \count($trace); $i < $count; ++$i) { + $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : ''; + $type = isset($trace[$i]['type']) ? $trace[$i]['type'] : ''; + $function = isset($trace[$i]['function']) ? $trace[$i]['function'] : ''; + $file = isset($trace[$i]['file']) ? $trace[$i]['file'] : 'n/a'; + $line = isset($trace[$i]['line']) ? $trace[$i]['line'] : 'n/a'; + $output->writeln(\sprintf(' %s%s at %s:%s', $class, $function ? $type . $function . '()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); + } + $output->writeln('', OutputInterface::VERBOSITY_QUIET); + } + } while ($e = $e->getPrevious()); + } + /** + * Configures the input and output instances based on the user arguments and options. + */ + protected function configureIO(InputInterface $input, OutputInterface $output) + { + if (\true === $input->hasParameterOption(['--ansi'], \true)) { + $output->setDecorated(\true); + } elseif (\true === $input->hasParameterOption(['--no-ansi'], \true)) { + $output->setDecorated(\false); + } + if (\true === $input->hasParameterOption(['--no-interaction', '-n'], \true)) { + $input->setInteractive(\false); + } + switch ($shellVerbosity = (int) \getenv('SHELL_VERBOSITY')) { + case -1: + $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); + break; + case 1: + $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); + break; + case 2: + $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); + break; + case 3: + $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); + break; + default: + $shellVerbosity = 0; + break; + } + if (\true === $input->hasParameterOption(['--quiet', '-q'], \true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); + $shellVerbosity = -1; + } else { + if ($input->hasParameterOption('-vvv', \true) || $input->hasParameterOption('--verbose=3', \true) || 3 === $input->getParameterOption('--verbose', \false, \true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); + $shellVerbosity = 3; + } elseif ($input->hasParameterOption('-vv', \true) || $input->hasParameterOption('--verbose=2', \true) || 2 === $input->getParameterOption('--verbose', \false, \true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); + $shellVerbosity = 2; + } elseif ($input->hasParameterOption('-v', \true) || $input->hasParameterOption('--verbose=1', \true) || $input->hasParameterOption('--verbose', \true) || $input->getParameterOption('--verbose', \false, \true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); + $shellVerbosity = 1; + } + } + if (-1 === $shellVerbosity) { + $input->setInteractive(\false); + } + if (\function_exists('putenv')) { + @\putenv('SHELL_VERBOSITY=' . $shellVerbosity); + } + $_ENV['SHELL_VERBOSITY'] = $shellVerbosity; + $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity; + } + /** + * Runs the current command. + * + * If an event dispatcher has been attached to the application, + * events are also dispatched during the life-cycle of the command. + * + * @return int 0 if everything went fine, or an error code + */ + protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output) + { + foreach ($command->getHelperSet() as $helper) { + if ($helper instanceof InputAwareInterface) { + $helper->setInput($input); + } + } + if ($command instanceof SignalableCommandInterface && ($this->signalsToDispatchEvent || $command->getSubscribedSignals())) { + if (!$this->signalRegistry) { + throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); + } + if ($this->dispatcher) { + foreach ($this->signalsToDispatchEvent as $signal) { + $event = new ConsoleSignalEvent($command, $input, $output, $signal); + $this->signalRegistry->register($signal, function ($signal, $hasNext) use($event) { + $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL); + // No more handlers, we try to simulate PHP default behavior + if (!$hasNext) { + if (!\in_array($signal, [\SIGUSR1, \SIGUSR2], \true)) { + exit(0); + } + } + }); + } + } + foreach ($command->getSubscribedSignals() as $signal) { + $this->signalRegistry->register($signal, [$command, 'handleSignal']); + } + } + if (null === $this->dispatcher) { + return $command->run($input, $output); + } + // bind before the console.command event, so the listeners have access to input options/arguments + try { + $command->mergeApplicationDefinition(); + $input->bind($command->getDefinition()); + } catch (ExceptionInterface $e) { + // ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition + } + $event = new ConsoleCommandEvent($command, $input, $output); + $e = null; + try { + $this->dispatcher->dispatch($event, ConsoleEvents::COMMAND); + if ($event->commandShouldRun()) { + $exitCode = $command->run($input, $output); + } else { + $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED; + } + } catch (\Exception $e) { + $event = new ConsoleErrorEvent($input, $output, $e, $command); + $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); + $e = $event->getError(); + if (0 === ($exitCode = $event->getExitCode())) { + $e = null; + } + } catch (\Error $e) { + $event = new ConsoleErrorEvent($input, $output, $e, $command); + $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); + $e = $event->getError(); + if (0 === ($exitCode = $event->getExitCode())) { + $e = null; + } + } + $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode); + $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE); + if (null !== $e) { + throw $e; + } + return $event->getExitCode(); + } + /** + * Gets the name of the command based on input. + * + * @return string|null + */ + protected function getCommandName(InputInterface $input) + { + return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument(); + } + /** + * Gets the default input definition. + * + * @return InputDefinition An InputDefinition instance + */ + protected function getDefaultInputDefinition() + { + return new InputDefinition([new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display help for the given command. When no command is given display help for the ' . $this->defaultCommand . ' command'), new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'), new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'), new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', \false), new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question')]); + } + /** + * Gets the default commands that should always be available. + * + * @return Command[] An array of default Command instances + */ + protected function getDefaultCommands() + { + return [new HelpCommand(), new ListCommand()]; + } + /** + * Gets the default helper set with the helpers that should always be available. + * + * @return HelperSet A HelperSet instance + */ + protected function getDefaultHelperSet() + { + return new HelperSet([new FormatterHelper(), new DebugFormatterHelper(), new ProcessHelper(), new QuestionHelper()]); + } + /** + * Returns abbreviated suggestions in string format. + */ + private function getAbbreviationSuggestions(array $abbrevs) + { + $phabelReturn = ' ' . \implode("\n ", $abbrevs); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Returns the namespace part of the command name. + * + * This method is not part of public API and should not be used directly. + * + * @return string The namespace of the command + */ + public function extractNamespace($name, $limit = null) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_null($limit)) { + if (!\is_int($limit)) { + if (!(\is_bool($limit) || \is_numeric($limit))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($limit) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($limit) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $limit = (int) $limit; + } + } + } + $parts = \explode(':', $name, -1); + return \implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit)); + } + /** + * Finds alternative of $name among $collection, + * if nothing is found in $collection, try in $abbrevs. + * + * @return string[] A sorted array of similar string + */ + private function findAlternatives($name, $collection) + { + if (!(\is_array($collection) || $collection instanceof \Traversable)) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($collection) must be of type iterable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($collection) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $threshold = 1000.0; + $alternatives = []; + $collectionParts = []; + foreach ($collection as $item) { + $collectionParts[$item] = \explode(':', $item); + } + foreach (\explode(':', $name) as $i => $subname) { + foreach ($collectionParts as $collectionName => $parts) { + $exists = isset($alternatives[$collectionName]); + if (!isset($parts[$i]) && $exists) { + $alternatives[$collectionName] += $threshold; + continue; + } elseif (!isset($parts[$i])) { + continue; + } + $lev = \levenshtein($subname, $parts[$i]); + if ($lev <= \strlen($subname) / 3 || '' !== $subname && \str_contains($parts[$i], $subname)) { + $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev; + } elseif ($exists) { + $alternatives[$collectionName] += $threshold; + } + } + } + foreach ($collection as $item) { + $lev = \levenshtein($name, $item); + if ($lev <= \strlen($name) / 3 || \str_contains($item, $name)) { + $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev; + } + } + $alternatives = \array_filter($alternatives, function ($lev) use($threshold) { + return $lev < 2 * $threshold; + }); + \ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE); + $phabelReturn = \array_keys($alternatives); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Sets the default Command name. + * + * @return self + */ + public function setDefaultCommand($commandName, $isSingleCommand = \false) + { + if (!\is_string($commandName)) { + if (!(\is_string($commandName) || \is_object($commandName) && \method_exists($commandName, '__toString') || (\is_bool($commandName) || \is_numeric($commandName)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($commandName) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($commandName) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $commandName = (string) $commandName; + } + } + if (!\is_bool($isSingleCommand)) { + if (!(\is_bool($isSingleCommand) || \is_numeric($isSingleCommand) || \is_string($isSingleCommand))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($isSingleCommand) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($isSingleCommand) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $isSingleCommand = (bool) $isSingleCommand; + } + } + $this->defaultCommand = \explode('|', \ltrim($commandName, '|'))[0]; + if ($isSingleCommand) { + // Ensure the command exist + $this->find($commandName); + $this->singleCommand = \true; + } + return $this; + } + /** + * @internal + */ + public function isSingleCommand() + { + $phabelReturn = $this->singleCommand; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + private function splitStringByWidth($string, $width) + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + if (!\is_int($width)) { + if (!(\is_bool($width) || \is_numeric($width))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($width) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($width) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $width = (int) $width; + } + } + // str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly. + // additionally, array_slice() is not enough as some character has doubled width. + // we need a function to split string not by character count but by string width + if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) { + $phabelReturn = \str_split($string, $width); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $utf8String = \mb_convert_encoding($string, 'utf8', $encoding); + $lines = []; + $line = ''; + $offset = 0; + while (\preg_match('/.{1,10000}/u', $utf8String, $m, 0, $offset)) { + $offset += \strlen($m[0]); + foreach (\preg_split('//u', $m[0]) as $char) { + // test if $char could be appended to current line + if (\mb_strwidth($line . $char, 'utf8') <= $width) { + $line .= $char; + continue; + } + // if not, push current line to array and make new line + $lines[] = \str_pad($line, $width); + $line = $char; + } + } + $lines[] = \count($lines) ? \str_pad($line, $width) : $line; + \mb_convert_variables($encoding, 'utf8', $lines); + $phabelReturn = $lines; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Returns all namespaces of the command name. + * + * @return string[] The namespaces of the command + */ + private function extractAllNamespaces($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + // -1 as third argument is needed to skip the command short name when exploding + $parts = \explode(':', $name, -1); + $namespaces = []; + foreach ($parts as $part) { + if (\count($namespaces)) { + $namespaces[] = \end($namespaces) . ':' . $part; + } else { + $namespaces[] = $part; + } + } + $phabelReturn = $namespaces; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function init() + { + if ($this->initialized) { + return; + } + $this->initialized = \true; + foreach ($this->getDefaultCommands() as $command) { + $this->add($command); + } + } +} diff --git a/vendor-bundle/symfony/console/Attribute/AsCommand.php b/vendor-bundle/symfony/console/Attribute/AsCommand.php new file mode 100644 index 000000000..6354721d2 --- /dev/null +++ b/vendor-bundle/symfony/console/Attribute/AsCommand.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Attribute; + +/** + * Service tag to autoconfigure commands. + */ +#[\Attribute(\Attribute::TARGET_CLASS)] +class AsCommand +{ + public function __construct(public $name, public $description = null, array $aliases = [], $hidden = \false) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_null($description)) { + if (!\is_string($description)) { + if (!(\is_string($description) || \is_object($description) && \method_exists($description, '__toString') || (\is_bool($description) || \is_numeric($description)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($description) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($description) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $description = (string) $description; + } + } + } + if (!\is_bool($hidden)) { + if (!(\is_bool($hidden) || \is_numeric($hidden) || \is_string($hidden))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($hidden) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($hidden) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $hidden = (bool) $hidden; + } + } + if (!$hidden && !$aliases) { + return; + } + $name = \explode('|', $name); + $name = \array_merge($name, $aliases); + if ($hidden && '' !== $name[0]) { + \array_unshift($name, ''); + } + $this->name = \implode('|', $name); + } +} diff --git a/vendor-bundle/symfony/console/CI/GithubActionReporter.php b/vendor-bundle/symfony/console/CI/GithubActionReporter.php new file mode 100644 index 000000000..085f52cf4 --- /dev/null +++ b/vendor-bundle/symfony/console/CI/GithubActionReporter.php @@ -0,0 +1,227 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\CI; + +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * Utility class for Github actions. + * + * @author Maxime Steinhausser + */ +class GithubActionReporter +{ + private $output; + /** + * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L80-L85 + */ + const ESCAPED_DATA = ['%' => '%25', "\r" => '%0D', "\n" => '%0A']; + /** + * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L87-L94 + */ + const ESCAPED_PROPERTIES = ['%' => '%25', "\r" => '%0D', "\n" => '%0A', ':' => '%3A', ',' => '%2C']; + public function __construct(OutputInterface $output) + { + $this->output = $output; + } + public static function isGithubActionEnvironment() + { + $phabelReturn = \false !== \getenv('GITHUB_ACTIONS'); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Output an error using the Github annotations format. + * + * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message + */ + public function error($message, $file = null, $line = null, $col = null) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_null($file)) { + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($file) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $file = (string) $file; + } + } + } + if (!\is_null($line)) { + if (!\is_int($line)) { + if (!(\is_bool($line) || \is_numeric($line))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($line) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($line) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $line = (int) $line; + } + } + } + if (!\is_null($col)) { + if (!\is_int($col)) { + if (!(\is_bool($col) || \is_numeric($col))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($col) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($col) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $col = (int) $col; + } + } + } + $this->log('error', $message, $file, $line, $col); + } + /** + * Output a warning using the Github annotations format. + * + * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message + */ + public function warning($message, $file = null, $line = null, $col = null) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_null($file)) { + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($file) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $file = (string) $file; + } + } + } + if (!\is_null($line)) { + if (!\is_int($line)) { + if (!(\is_bool($line) || \is_numeric($line))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($line) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($line) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $line = (int) $line; + } + } + } + if (!\is_null($col)) { + if (!\is_int($col)) { + if (!(\is_bool($col) || \is_numeric($col))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($col) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($col) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $col = (int) $col; + } + } + } + $this->log('warning', $message, $file, $line, $col); + } + /** + * Output a debug log using the Github annotations format. + * + * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message + */ + public function debug($message, $file = null, $line = null, $col = null) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_null($file)) { + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($file) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $file = (string) $file; + } + } + } + if (!\is_null($line)) { + if (!\is_int($line)) { + if (!(\is_bool($line) || \is_numeric($line))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($line) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($line) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $line = (int) $line; + } + } + } + if (!\is_null($col)) { + if (!\is_int($col)) { + if (!(\is_bool($col) || \is_numeric($col))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($col) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($col) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $col = (int) $col; + } + } + } + $this->log('debug', $message, $file, $line, $col); + } + private function log($type, $message, $file = null, $line = null, $col = null) + { + if (!\is_string($type)) { + if (!(\is_string($type) || \is_object($type) && \method_exists($type, '__toString') || (\is_bool($type) || \is_numeric($type)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($type) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (string) $type; + } + } + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_null($file)) { + if (!\is_string($file)) { + if (!(\is_string($file) || \is_object($file) && \method_exists($file, '__toString') || (\is_bool($file) || \is_numeric($file)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($file) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($file) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $file = (string) $file; + } + } + } + if (!\is_null($line)) { + if (!\is_int($line)) { + if (!(\is_bool($line) || \is_numeric($line))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($line) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($line) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $line = (int) $line; + } + } + } + if (!\is_null($col)) { + if (!\is_int($col)) { + if (!(\is_bool($col) || \is_numeric($col))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($col) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($col) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $col = (int) $col; + } + } + } + // Some values must be encoded. + $message = \strtr($message, self::ESCAPED_DATA); + if (!$file) { + // No file provided, output the message solely: + $this->output->writeln(\sprintf('::%s::%s', $type, $message)); + return; + } + $this->output->writeln(\sprintf('::%s file=%s,line=%s,col=%s::%s', $type, \strtr($file, self::ESCAPED_PROPERTIES), \strtr(isset($line) ? $line : 1, self::ESCAPED_PROPERTIES), \strtr(isset($col) ? $col : 0, self::ESCAPED_PROPERTIES), $message)); + } +} diff --git a/vendor-bundle/symfony/console/Color.php b/vendor-bundle/symfony/console/Color.php new file mode 100644 index 000000000..e75fc7161 --- /dev/null +++ b/vendor-bundle/symfony/console/Color.php @@ -0,0 +1,331 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * @author Fabien Potencier + */ +final class Color +{ + const COLORS = ['black' => 0, 'red' => 1, 'green' => 2, 'yellow' => 3, 'blue' => 4, 'magenta' => 5, 'cyan' => 6, 'white' => 7, 'default' => 9]; + const BRIGHT_COLORS = ['gray' => 0, 'bright-red' => 1, 'bright-green' => 2, 'bright-yellow' => 3, 'bright-blue' => 4, 'bright-magenta' => 5, 'bright-cyan' => 6, 'bright-white' => 7]; + const AVAILABLE_OPTIONS = ['bold' => ['set' => 1, 'unset' => 22], 'underscore' => ['set' => 4, 'unset' => 24], 'blink' => ['set' => 5, 'unset' => 25], 'reverse' => ['set' => 7, 'unset' => 27], 'conceal' => ['set' => 8, 'unset' => 28]]; + private $foreground; + private $background; + private $options = []; + public function __construct($foreground = '', $background = '', array $options = []) + { + if (!\is_string($foreground)) { + if (!(\is_string($foreground) || \is_object($foreground) && \method_exists($foreground, '__toString') || (\is_bool($foreground) || \is_numeric($foreground)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($foreground) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($foreground) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $foreground = (string) $foreground; + } + } + if (!\is_string($background)) { + if (!(\is_string($background) || \is_object($background) && \method_exists($background, '__toString') || (\is_bool($background) || \is_numeric($background)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($background) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($background) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $background = (string) $background; + } + } + $this->foreground = $this->parseColor($foreground); + $this->background = $this->parseColor($background, \true); + foreach ($options as $option) { + if (!isset(self::AVAILABLE_OPTIONS[$option])) { + throw new InvalidArgumentException(\sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, \implode(', ', \array_keys(self::AVAILABLE_OPTIONS)))); + } + $this->options[$option] = self::AVAILABLE_OPTIONS[$option]; + } + } + public function apply($text) + { + if (!\is_string($text)) { + if (!(\is_string($text) || \is_object($text) && \method_exists($text, '__toString') || (\is_bool($text) || \is_numeric($text)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($text) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($text) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $text = (string) $text; + } + } + $phabelReturn = $this->set() . $text . $this->unset(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function set() + { + $setCodes = []; + if ('' !== $this->foreground) { + $setCodes[] = $this->foreground; + } + if ('' !== $this->background) { + $setCodes[] = $this->background; + } + foreach ($this->options as $option) { + $setCodes[] = $option['set']; + } + if (0 === \count($setCodes)) { + $phabelReturn = ''; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \sprintf("\x1b[%sm", \implode(';', $setCodes)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function unset() + { + $unsetCodes = []; + if ('' !== $this->foreground) { + $unsetCodes[] = 39; + } + if ('' !== $this->background) { + $unsetCodes[] = 49; + } + foreach ($this->options as $option) { + $unsetCodes[] = $option['unset']; + } + if (0 === \count($unsetCodes)) { + $phabelReturn = ''; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \sprintf("\x1b[%sm", \implode(';', $unsetCodes)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + private function parseColor($color, $background = \false) + { + if (!\is_string($color)) { + if (!(\is_string($color) || \is_object($color) && \method_exists($color, '__toString') || (\is_bool($color) || \is_numeric($color)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($color) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($color) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $color = (string) $color; + } + } + if (!\is_bool($background)) { + if (!(\is_bool($background) || \is_numeric($background) || \is_string($background))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($background) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($background) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $background = (bool) $background; + } + } + if ('' === $color) { + $phabelReturn = ''; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if ('#' === $color[0]) { + $color = \substr($color, 1); + if (3 === \strlen($color)) { + $color = $color[0] . $color[0] . $color[1] . $color[1] . $color[2] . $color[2]; + } + if (6 !== \strlen($color)) { + throw new InvalidArgumentException(\sprintf('Invalid "%s" color.', $color)); + } + $phabelReturn = ($background ? '4' : '3') . $this->convertHexColorToAnsi(\hexdec($color)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (isset(self::COLORS[$color])) { + $phabelReturn = ($background ? '4' : '3') . self::COLORS[$color]; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (isset(self::BRIGHT_COLORS[$color])) { + $phabelReturn = ($background ? '10' : '9') . self::BRIGHT_COLORS[$color]; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + throw new InvalidArgumentException(\sprintf('Invalid "%s" color; expected one of (%s).', $color, \implode(', ', \array_merge(\array_keys(self::COLORS), \array_keys(self::BRIGHT_COLORS))))); + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + private function convertHexColorToAnsi($color) + { + if (!\is_int($color)) { + if (!(\is_bool($color) || \is_numeric($color))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($color) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($color) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $color = (int) $color; + } + } + $r = $color >> 16 & 255; + $g = $color >> 8 & 255; + $b = $color & 255; + // see https://github.com/termstandard/colors/ for more information about true color support + if ('truecolor' !== \getenv('COLORTERM')) { + $phabelReturn = (string) $this->degradeHexColorToAnsi($r, $g, $b); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \sprintf('8;2;%d;%d;%d', $r, $g, $b); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + private function degradeHexColorToAnsi($r, $g, $b) + { + if (!\is_int($r)) { + if (!(\is_bool($r) || \is_numeric($r))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($r) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($r) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $r = (int) $r; + } + } + if (!\is_int($g)) { + if (!(\is_bool($g) || \is_numeric($g))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($g) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($g) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $g = (int) $g; + } + } + if (!\is_int($b)) { + if (!(\is_bool($b) || \is_numeric($b))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($b) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($b) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $b = (int) $b; + } + } + if (0 === \round($this->getSaturation($r, $g, $b) / 50)) { + $phabelReturn = 0; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \round($b / 255) << 2 | \round($g / 255) << 1 | \round($r / 255); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + private function getSaturation($r, $g, $b) + { + if (!\is_int($r)) { + if (!(\is_bool($r) || \is_numeric($r))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($r) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($r) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $r = (int) $r; + } + } + if (!\is_int($g)) { + if (!(\is_bool($g) || \is_numeric($g))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($g) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($g) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $g = (int) $g; + } + } + if (!\is_int($b)) { + if (!(\is_bool($b) || \is_numeric($b))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($b) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($b) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $b = (int) $b; + } + } + $r = $r / 255; + $g = $g / 255; + $b = $b / 255; + $v = \max($r, $g, $b); + if (0 === ($diff = $v - \min($r, $g, $b))) { + $phabelReturn = 0; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = (int) $diff * 100 / $v; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Command/Command.php b/vendor-bundle/symfony/console/Command/Command.php new file mode 100644 index 000000000..52e58c48c --- /dev/null +++ b/vendor-bundle/symfony/console/Command/Command.php @@ -0,0 +1,758 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Command; + +use Phabel\Symfony\Component\Console\Application; +use Phabel\Symfony\Component\Console\Attribute\AsCommand; +use Phabel\Symfony\Component\Console\Exception\ExceptionInterface; +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Exception\LogicException; +use Phabel\Symfony\Component\Console\Helper\HelperSet; +use Phabel\Symfony\Component\Console\Input\InputArgument; +use Phabel\Symfony\Component\Console\Input\InputDefinition; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Input\InputOption; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * Base class for all commands. + * + * @author Fabien Potencier + */ +class Command +{ + // see https://tldp.org/LDP/abs/html/exitcodes.html + const SUCCESS = 0; + const FAILURE = 1; + const INVALID = 2; + /** + * @var string|null The default command name + */ + protected static $defaultName; + /** + * @var string|null The default command description + */ + protected static $defaultDescription; + private $application; + private $name; + private $processTitle; + private $aliases = []; + private $definition; + private $hidden = \false; + private $help = ''; + private $description = ''; + private $fullDefinition; + private $ignoreValidationErrors = \false; + private $code; + private $synopsis = []; + private $usages = []; + private $helperSet; + /** + * @return string|null The default command name or null when no default name is set + */ + public static function getDefaultName() + { + $class = static::class; + if (\PHP_VERSION_ID >= 80000 && ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class))) { + return $attribute[0]->newInstance()->name; + } + $r = new \ReflectionProperty($class, 'defaultName'); + return $class === $r->class ? static::$defaultName : null; + } + /** + * @return string|null The default command description or null when no default description is set + */ + public static function getDefaultDescription() + { + $class = static::class; + if (\PHP_VERSION_ID >= 80000 && ($attribute = (new \ReflectionClass($class))->getAttributes(AsCommand::class))) { + $phabelReturn = $attribute[0]->newInstance()->description; + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } + $r = new \ReflectionProperty($class, 'defaultDescription'); + $phabelReturn = $class === $r->class ? static::$defaultDescription : null; + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } + /** + * @param string|null $name The name of the command; passing null means it must be set in configure() + * + * @throws LogicException When the command name is empty + */ + public function __construct($name = null) + { + if (!\is_null($name)) { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + } + $this->definition = new InputDefinition(); + if (null === $name && null !== ($name = static::getDefaultName())) { + $aliases = \explode('|', $name); + if ('' === ($name = \array_shift($aliases))) { + $this->setHidden(\true); + $name = \array_shift($aliases); + } + $this->setAliases($aliases); + } + if (null !== $name) { + $this->setName($name); + } + if ('' === $this->description) { + $this->setDescription(NULL !== ($phabel_187db3ce20c580af = static::getDefaultDescription()) ? $phabel_187db3ce20c580af : ''); + } + $this->configure(); + } + /** + * Ignores validation errors. + * + * This is mainly useful for the help command. + */ + public function ignoreValidationErrors() + { + $this->ignoreValidationErrors = \true; + } + public function setApplication(Application $application = null) + { + $this->application = $application; + if ($application) { + $this->setHelperSet($application->getHelperSet()); + } else { + $this->helperSet = null; + } + $this->fullDefinition = null; + } + public function setHelperSet(HelperSet $helperSet) + { + $this->helperSet = $helperSet; + } + /** + * Gets the helper set. + * + * @return HelperSet|null A HelperSet instance + */ + public function getHelperSet() + { + return $this->helperSet; + } + /** + * Gets the application instance for this command. + * + * @return Application|null An Application instance + */ + public function getApplication() + { + return $this->application; + } + /** + * Checks whether the command is enabled or not in the current environment. + * + * Override this to check for x or y and return false if the command can not + * run properly under the current conditions. + * + * @return bool + */ + public function isEnabled() + { + return \true; + } + /** + * Configures the current command. + */ + protected function configure() + { + } + /** + * Executes the current command. + * + * This method is not abstract because you can use this class + * as a concrete class. In this case, instead of defining the + * execute() method, you set the code to execute by passing + * a Closure to the setCode() method. + * + * @return int 0 if everything went fine, or an exit code + * + * @throws LogicException When this abstract method is not implemented + * + * @see setCode() + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + throw new LogicException('You must override the execute() method in the concrete command class.'); + } + /** + * Interacts with the user. + * + * This method is executed before the InputDefinition is validated. + * This means that this is the only place where the command can + * interactively ask for values of missing required arguments. + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + } + /** + * Initializes the command after the input has been bound and before the input + * is validated. + * + * This is mainly useful when a lot of commands extends one main command + * where some things need to be initialized based on the input arguments and options. + * + * @see InputInterface::bind() + * @see InputInterface::validate() + */ + protected function initialize(InputInterface $input, OutputInterface $output) + { + } + /** + * Runs the command. + * + * The code to execute is either defined directly with the + * setCode() method or by overriding the execute() method + * in a sub-class. + * + * @return int The command exit code + * + * @throws \Exception When binding input fails. Bypass this by calling {@link ignoreValidationErrors()}. + * + * @see setCode() + * @see execute() + */ + public function run(InputInterface $input, OutputInterface $output) + { + // add the application arguments and options + $this->mergeApplicationDefinition(); + // bind the input against the command specific arguments/options + try { + $input->bind($this->getDefinition()); + } catch (ExceptionInterface $e) { + if (!$this->ignoreValidationErrors) { + throw $e; + } + } + $this->initialize($input, $output); + if (null !== $this->processTitle) { + if (\function_exists('cli_set_process_title')) { + if (!@\cli_set_process_title($this->processTitle)) { + if ('Darwin' === \PHP_OS) { + $output->writeln('Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.', OutputInterface::VERBOSITY_VERY_VERBOSE); + } else { + \cli_set_process_title($this->processTitle); + } + } + } elseif (\function_exists('Phabel\\setproctitle')) { + setproctitle($this->processTitle); + } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) { + $output->writeln('Install the proctitle PECL to be able to change the process title.'); + } + } + if ($input->isInteractive()) { + $this->interact($input, $output); + } + // The command name argument is often omitted when a command is executed directly with its run() method. + // It would fail the validation if we didn't make sure the command argument is present, + // since it's required by the application. + if ($input->hasArgument('command') && null === $input->getArgument('command')) { + $input->setArgument('command', $this->getName()); + } + $input->validate(); + if ($this->code) { + $phabel_8da28ba4668d03f7 = $this->code; + $statusCode = $phabel_8da28ba4668d03f7($input, $output); + } else { + $statusCode = $this->execute($input, $output); + if (!\is_int($statusCode)) { + throw new \TypeError(\sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, \get_debug_type($statusCode))); + } + } + return \is_numeric($statusCode) ? (int) $statusCode : 0; + } + /** + * Sets the code to execute when running this command. + * + * If this method is used, it overrides the code defined + * in the execute() method. + * + * @param callable $code A callable(InputInterface $input, OutputInterface $output) + * + * @return $this + * + * @throws InvalidArgumentException + * + * @see execute() + */ + public function setCode(callable $code) + { + if ($code instanceof \Closure) { + $r = new \ReflectionFunction($code); + if (null === $r->getClosureThis()) { + \set_error_handler(static function () { + }); + try { + if ($c = \Closure::bind($code, $this)) { + $code = $c; + } + } finally { + \restore_error_handler(); + } + } + } + $this->code = $code; + return $this; + } + /** + * Merges the application definition with the command definition. + * + * This method is not part of public API and should not be used directly. + * + * @param bool $mergeArgs Whether to merge or not the Application definition arguments to Command definition arguments + * + * @internal + */ + public function mergeApplicationDefinition($mergeArgs = \true) + { + if (!\is_bool($mergeArgs)) { + if (!(\is_bool($mergeArgs) || \is_numeric($mergeArgs) || \is_string($mergeArgs))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($mergeArgs) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mergeArgs) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $mergeArgs = (bool) $mergeArgs; + } + } + if (null === $this->application) { + return; + } + $this->fullDefinition = new InputDefinition(); + $this->fullDefinition->setOptions($this->definition->getOptions()); + $this->fullDefinition->addOptions($this->application->getDefinition()->getOptions()); + if ($mergeArgs) { + $this->fullDefinition->setArguments($this->application->getDefinition()->getArguments()); + $this->fullDefinition->addArguments($this->definition->getArguments()); + } else { + $this->fullDefinition->setArguments($this->definition->getArguments()); + } + } + /** + * Sets an array of argument and option instances. + * + * @param array|InputDefinition $definition An array of argument and option instances or a definition instance + * + * @return $this + */ + public function setDefinition($definition) + { + if ($definition instanceof InputDefinition) { + $this->definition = $definition; + } else { + $this->definition->setDefinition($definition); + } + $this->fullDefinition = null; + return $this; + } + /** + * Gets the InputDefinition attached to this Command. + * + * @return InputDefinition An InputDefinition instance + */ + public function getDefinition() + { + return isset($this->fullDefinition) ? $this->fullDefinition : $this->getNativeDefinition(); + } + /** + * Gets the InputDefinition to be used to create representations of this Command. + * + * Can be overridden to provide the original command representation when it would otherwise + * be changed by merging with the application InputDefinition. + * + * This method is not part of public API and should not be used directly. + * + * @return InputDefinition An InputDefinition instance + */ + public function getNativeDefinition() + { + if (null === $this->definition) { + throw new LogicException(\sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class)); + } + return $this->definition; + } + /** + * Adds an argument. + * + * @param int|null $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL + * @param mixed $default The default value (for InputArgument::OPTIONAL mode only) + * + * @throws InvalidArgumentException When argument mode is not valid + * + * @return $this + */ + public function addArgument($name, $mode = null, $description = '', $default = null) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_null($mode)) { + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($mode) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $mode = (int) $mode; + } + } + } + if (!\is_string($description)) { + if (!(\is_string($description) || \is_object($description) && \method_exists($description, '__toString') || (\is_bool($description) || \is_numeric($description)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($description) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($description) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $description = (string) $description; + } + } + $this->definition->addArgument(new InputArgument($name, $mode, $description, $default)); + if (null !== $this->fullDefinition) { + $this->fullDefinition->addArgument(new InputArgument($name, $mode, $description, $default)); + } + return $this; + } + /** + * Adds an option. + * + * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts + * @param int|null $mode The option mode: One of the InputOption::VALUE_* constants + * @param mixed $default The default value (must be null for InputOption::VALUE_NONE) + * + * @throws InvalidArgumentException If option mode is invalid or incompatible + * + * @return $this + */ + public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_null($mode)) { + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($mode) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $mode = (int) $mode; + } + } + } + if (!\is_string($description)) { + if (!(\is_string($description) || \is_object($description) && \method_exists($description, '__toString') || (\is_bool($description) || \is_numeric($description)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($description) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($description) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $description = (string) $description; + } + } + $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default)); + if (null !== $this->fullDefinition) { + $this->fullDefinition->addOption(new InputOption($name, $shortcut, $mode, $description, $default)); + } + return $this; + } + /** + * Sets the name of the command. + * + * This method can set both the namespace and the name if + * you separate them by a colon (:) + * + * $command->setName('foo:bar'); + * + * @return $this + * + * @throws InvalidArgumentException When the name is invalid + */ + public function setName($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $this->validateName($name); + $this->name = $name; + return $this; + } + /** + * Sets the process title of the command. + * + * This feature should be used only when creating a long process command, + * like a daemon. + * + * @return $this + */ + public function setProcessTitle($title) + { + if (!\is_string($title)) { + if (!(\is_string($title) || \is_object($title) && \method_exists($title, '__toString') || (\is_bool($title) || \is_numeric($title)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($title) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($title) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $title = (string) $title; + } + } + $this->processTitle = $title; + return $this; + } + /** + * Returns the command name. + * + * @return string|null + */ + public function getName() + { + return $this->name; + } + /** + * @param bool $hidden Whether or not the command should be hidden from the list of commands + * The default value will be true in Symfony 6.0 + * + * @return $this + * + * @final since Symfony 5.1 + */ + public function setHidden($hidden) + { + if (!\is_bool($hidden)) { + if (!(\is_bool($hidden) || \is_numeric($hidden) || \is_string($hidden))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($hidden) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($hidden) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $hidden = (bool) $hidden; + } + } + $this->hidden = $hidden; + return $this; + } + /** + * @return bool whether the command should be publicly shown or not + */ + public function isHidden() + { + return $this->hidden; + } + /** + * Sets the description for the command. + * + * @return $this + */ + public function setDescription($description) + { + if (!\is_string($description)) { + if (!(\is_string($description) || \is_object($description) && \method_exists($description, '__toString') || (\is_bool($description) || \is_numeric($description)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($description) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($description) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $description = (string) $description; + } + } + $this->description = $description; + return $this; + } + /** + * Returns the description for the command. + * + * @return string The description for the command + */ + public function getDescription() + { + return $this->description; + } + /** + * Sets the help for the command. + * + * @return $this + */ + public function setHelp($help) + { + if (!\is_string($help)) { + if (!(\is_string($help) || \is_object($help) && \method_exists($help, '__toString') || (\is_bool($help) || \is_numeric($help)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($help) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($help) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $help = (string) $help; + } + } + $this->help = $help; + return $this; + } + /** + * Returns the help for the command. + * + * @return string The help for the command + */ + public function getHelp() + { + return $this->help; + } + /** + * Returns the processed help for the command replacing the %command.name% and + * %command.full_name% patterns with the real values dynamically. + * + * @return string The processed help for the command + */ + public function getProcessedHelp() + { + $name = $this->name; + $isSingleCommand = $this->application && $this->application->isSingleCommand(); + $placeholders = ['%command.name%', '%command.full_name%']; + $replacements = [$name, $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'] . ' ' . $name]; + return \str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription()); + } + /** + * Sets the aliases for the command. + * + * @param string[] $aliases An array of aliases for the command + * + * @return $this + * + * @throws InvalidArgumentException When an alias is invalid + */ + public function setAliases($aliases) + { + if (!(\is_array($aliases) || $aliases instanceof \Traversable)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($aliases) must be of type iterable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($aliases) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $list = []; + foreach ($aliases as $alias) { + $this->validateName($alias); + $list[] = $alias; + } + $this->aliases = \is_array($aliases) ? $aliases : $list; + return $this; + } + /** + * Returns the aliases for the command. + * + * @return array An array of aliases for the command + */ + public function getAliases() + { + return $this->aliases; + } + /** + * Returns the synopsis for the command. + * + * @param bool $short Whether to show the short version of the synopsis (with options folded) or not + * + * @return string The synopsis + */ + public function getSynopsis($short = \false) + { + if (!\is_bool($short)) { + if (!(\is_bool($short) || \is_numeric($short) || \is_string($short))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($short) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($short) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $short = (bool) $short; + } + } + $key = $short ? 'short' : 'long'; + if (!isset($this->synopsis[$key])) { + $this->synopsis[$key] = \trim(\sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); + } + return $this->synopsis[$key]; + } + /** + * Add a command usage example, it'll be prefixed with the command name. + * + * @return $this + */ + public function addUsage($usage) + { + if (!\is_string($usage)) { + if (!(\is_string($usage) || \is_object($usage) && \method_exists($usage, '__toString') || (\is_bool($usage) || \is_numeric($usage)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($usage) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($usage) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $usage = (string) $usage; + } + } + if (!\str_starts_with($usage, $this->name)) { + $usage = \sprintf('%s %s', $this->name, $usage); + } + $this->usages[] = $usage; + return $this; + } + /** + * Returns alternative usages of the command. + * + * @return array + */ + public function getUsages() + { + return $this->usages; + } + /** + * Gets a helper instance by name. + * + * @return mixed The helper value + * + * @throws LogicException if no HelperSet is defined + * @throws InvalidArgumentException if the helper is not defined + */ + public function getHelper($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (null === $this->helperSet) { + throw new LogicException(\sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name)); + } + return $this->helperSet->get($name); + } + /** + * Validates a command name. + * + * It must be non-empty and parts can optionally be separated by ":". + * + * @throws InvalidArgumentException When the name is invalid + */ + private function validateName($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\preg_match('/^[^\\:]++(\\:[^\\:]++)*$/', $name)) { + throw new InvalidArgumentException(\sprintf('Command name "%s" is invalid.', $name)); + } + } +} diff --git a/vendor-bundle/symfony/console/Command/HelpCommand.php b/vendor-bundle/symfony/console/Command/HelpCommand.php new file mode 100644 index 000000000..4fde753ef --- /dev/null +++ b/vendor-bundle/symfony/console/Command/HelpCommand.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Command; + +use Phabel\Symfony\Component\Console\Helper\DescriptorHelper; +use Phabel\Symfony\Component\Console\Input\InputArgument; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Input\InputOption; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * HelpCommand displays the help for a given command. + * + * @author Fabien Potencier + */ +class HelpCommand extends Command +{ + private $command; + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->ignoreValidationErrors(); + $this->setName('help')->setDefinition([new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help')])->setDescription('Display help for a command')->setHelp(<<<'EOF' +The %command.name% command displays help for a given command: + + %command.full_name% list + +You can also output the help in other formats by using the --format option: + + %command.full_name% --format=xml list + +To display the list of available commands, please use the list command. +EOF +); + } + public function setCommand(Command $command) + { + $this->command = $command; + } + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + if (null === $this->command) { + $this->command = $this->getApplication()->find($input->getArgument('command_name')); + } + $helper = new DescriptorHelper(); + $helper->describe($output, $this->command, ['format' => $input->getOption('format'), 'raw_text' => $input->getOption('raw')]); + $this->command = null; + return 0; + } +} diff --git a/vendor-bundle/symfony/console/Command/LazyCommand.php b/vendor-bundle/symfony/console/Command/LazyCommand.php new file mode 100644 index 000000000..3cade81ef --- /dev/null +++ b/vendor-bundle/symfony/console/Command/LazyCommand.php @@ -0,0 +1,373 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Command; + +use Phabel\Symfony\Component\Console\Application; +use Phabel\Symfony\Component\Console\Helper\HelperSet; +use Phabel\Symfony\Component\Console\Input\InputDefinition; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Nicolas Grekas + */ +final class LazyCommand extends Command +{ + private $command; + private $isEnabled; + public function __construct($name, array $aliases, $description, $isHidden, \Closure $commandFactory, $isEnabled = \true) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_string($description)) { + if (!(\is_string($description) || \is_object($description) && \method_exists($description, '__toString') || (\is_bool($description) || \is_numeric($description)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($description) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($description) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $description = (string) $description; + } + } + if (!\is_bool($isHidden)) { + if (!(\is_bool($isHidden) || \is_numeric($isHidden) || \is_string($isHidden))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($isHidden) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($isHidden) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $isHidden = (bool) $isHidden; + } + } + if (!\is_null($isEnabled)) { + if (!\is_bool($isEnabled)) { + if (!(\is_bool($isEnabled) || \is_numeric($isEnabled) || \is_string($isEnabled))) { + throw new \TypeError(__METHOD__ . '(): Argument #6 ($isEnabled) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($isEnabled) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $isEnabled = (bool) $isEnabled; + } + } + } + $this->setName($name)->setAliases($aliases)->setHidden($isHidden)->setDescription($description); + $this->command = $commandFactory; + $this->isEnabled = $isEnabled; + } + public function ignoreValidationErrors() + { + $this->getCommand()->ignoreValidationErrors(); + } + public function setApplication(Application $application = null) + { + if ($this->command instanceof parent) { + $this->command->setApplication($application); + } + parent::setApplication($application); + } + public function setHelperSet(HelperSet $helperSet) + { + if ($this->command instanceof parent) { + $this->command->setHelperSet($helperSet); + } + parent::setHelperSet($helperSet); + } + public function isEnabled() + { + $phabelReturn = isset($this->isEnabled) ? $this->isEnabled : $this->getCommand()->isEnabled(); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function run(InputInterface $input, OutputInterface $output) + { + $phabelReturn = $this->getCommand()->run($input, $output); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return $this + */ + public function setCode(callable $code) + { + $this->getCommand()->setCode($code); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @internal + */ + public function mergeApplicationDefinition($mergeArgs = \true) + { + if (!\is_bool($mergeArgs)) { + if (!(\is_bool($mergeArgs) || \is_numeric($mergeArgs) || \is_string($mergeArgs))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($mergeArgs) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mergeArgs) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $mergeArgs = (bool) $mergeArgs; + } + } + $this->getCommand()->mergeApplicationDefinition($mergeArgs); + } + /** + * @return $this + */ + public function setDefinition($definition) + { + $this->getCommand()->setDefinition($definition); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getDefinition() + { + $phabelReturn = $this->getCommand()->getDefinition(); + if (!$phabelReturn instanceof InputDefinition) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type InputDefinition, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getNativeDefinition() + { + $phabelReturn = $this->getCommand()->getNativeDefinition(); + if (!$phabelReturn instanceof InputDefinition) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type InputDefinition, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return $this + */ + public function addArgument($name, $mode = null, $description = '', $default = null) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_null($mode)) { + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($mode) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $mode = (int) $mode; + } + } + } + if (!\is_string($description)) { + if (!(\is_string($description) || \is_object($description) && \method_exists($description, '__toString') || (\is_bool($description) || \is_numeric($description)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($description) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($description) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $description = (string) $description; + } + } + $this->getCommand()->addArgument($name, $mode, $description, $default); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return $this + */ + public function addOption($name, $shortcut = null, $mode = null, $description = '', $default = null) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_null($mode)) { + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($mode) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $mode = (int) $mode; + } + } + } + if (!\is_string($description)) { + if (!(\is_string($description) || \is_object($description) && \method_exists($description, '__toString') || (\is_bool($description) || \is_numeric($description)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($description) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($description) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $description = (string) $description; + } + } + $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return $this + */ + public function setProcessTitle($title) + { + if (!\is_string($title)) { + if (!(\is_string($title) || \is_object($title) && \method_exists($title, '__toString') || (\is_bool($title) || \is_numeric($title)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($title) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($title) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $title = (string) $title; + } + } + $this->getCommand()->setProcessTitle($title); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return $this + */ + public function setHelp($help) + { + if (!\is_string($help)) { + if (!(\is_string($help) || \is_object($help) && \method_exists($help, '__toString') || (\is_bool($help) || \is_numeric($help)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($help) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($help) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $help = (string) $help; + } + } + $this->getCommand()->setHelp($help); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getHelp() + { + $phabelReturn = $this->getCommand()->getHelp(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function getProcessedHelp() + { + $phabelReturn = $this->getCommand()->getProcessedHelp(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function getSynopsis($short = \false) + { + if (!\is_bool($short)) { + if (!(\is_bool($short) || \is_numeric($short) || \is_string($short))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($short) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($short) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $short = (bool) $short; + } + } + $phabelReturn = $this->getCommand()->getSynopsis($short); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return $this + */ + public function addUsage($usage) + { + if (!\is_string($usage)) { + if (!(\is_string($usage) || \is_object($usage) && \method_exists($usage, '__toString') || (\is_bool($usage) || \is_numeric($usage)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($usage) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($usage) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $usage = (string) $usage; + } + } + $this->getCommand()->addUsage($usage); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getUsages() + { + $phabelReturn = $this->getCommand()->getUsages(); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return mixed + */ + public function getHelper($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + return $this->getCommand()->getHelper($name); + } + public function getCommand() + { + if (!$this->command instanceof \Closure) { + $phabelReturn = $this->command; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabel_9b2fc8900731f1a7 = $this->command; + $command = $this->command = $phabel_9b2fc8900731f1a7(); + $command->setApplication($this->getApplication()); + if (null !== $this->getHelperSet()) { + $command->setHelperSet($this->getHelperSet()); + } + $command->setName($this->getName())->setAliases($this->getAliases())->setHidden($this->isHidden())->setDescription($this->getDescription()); + // Will throw if the command is not correctly initialized. + $command->getDefinition(); + $phabelReturn = $command; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Command/ListCommand.php b/vendor-bundle/symfony/console/Command/ListCommand.php new file mode 100644 index 000000000..d3a5ae619 --- /dev/null +++ b/vendor-bundle/symfony/console/Command/ListCommand.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Command; + +use Phabel\Symfony\Component\Console\Helper\DescriptorHelper; +use Phabel\Symfony\Component\Console\Input\InputArgument; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Input\InputOption; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * ListCommand displays the list of all available commands for the application. + * + * @author Fabien Potencier + */ +class ListCommand extends Command +{ + /** + * {@inheritdoc} + */ + protected function configure() + { + $this->setName('list')->setDefinition([new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name'), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments')])->setDescription('List commands')->setHelp(<<<'EOF' +The %command.name% command lists all commands: + + %command.full_name% + +You can also display the commands for a specific namespace: + + %command.full_name% test + +You can also output the information in other formats by using the --format option: + + %command.full_name% --format=xml + +It's also possible to get raw list of commands (useful for embedding command runner): + + %command.full_name% --raw +EOF +); + } + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $helper = new DescriptorHelper(); + $helper->describe($output, $this->getApplication(), ['format' => $input->getOption('format'), 'raw_text' => $input->getOption('raw'), 'namespace' => $input->getArgument('namespace'), 'short' => $input->getOption('short')]); + return 0; + } +} diff --git a/vendor-bundle/symfony/console/Command/LockableTrait.php b/vendor-bundle/symfony/console/Command/LockableTrait.php new file mode 100644 index 000000000..ddcdd1379 --- /dev/null +++ b/vendor-bundle/symfony/console/Command/LockableTrait.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Command; + +use Phabel\Symfony\Component\Console\Exception\LogicException; +use Phabel\Symfony\Component\Lock\Lock; +use Phabel\Symfony\Component\Lock\LockFactory; +use Phabel\Symfony\Component\Lock\Store\FlockStore; +use Phabel\Symfony\Component\Lock\Store\SemaphoreStore; +/** + * Basic lock feature for commands. + * + * @author Geoffrey Brier + */ +trait LockableTrait +{ + /** @var Lock */ + private $lock; + /** + * Locks a command. + */ + private function lock($name = null, $blocking = \false) + { + if (!\is_null($name)) { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + } + if (!\is_bool($blocking)) { + if (!(\is_bool($blocking) || \is_numeric($blocking) || \is_string($blocking))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($blocking) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($blocking) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $blocking = (bool) $blocking; + } + } + if (!\class_exists(SemaphoreStore::class)) { + throw new LogicException('To enable the locking feature you must install the symfony/lock component.'); + } + if (null !== $this->lock) { + throw new LogicException('A lock is already in place.'); + } + if (SemaphoreStore::isSupported()) { + $store = new SemaphoreStore(); + } else { + $store = new FlockStore(); + } + $this->lock = (new LockFactory($store))->createLock($name ?: $this->getName()); + if (!$this->lock->acquire($blocking)) { + $this->lock = null; + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Releases the command lock if there is one. + */ + private function release() + { + if ($this->lock) { + $this->lock->release(); + $this->lock = null; + } + } +} diff --git a/vendor-bundle/symfony/console/Command/SignalableCommandInterface.php b/vendor-bundle/symfony/console/Command/SignalableCommandInterface.php new file mode 100644 index 000000000..47a60e1c9 --- /dev/null +++ b/vendor-bundle/symfony/console/Command/SignalableCommandInterface.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Command; + +/** + * Interface for command reacting to signal. + * + * @author Grégoire Pineau + */ +interface SignalableCommandInterface +{ + /** + * Returns the list of signals to subscribe. + */ + public function getSubscribedSignals(); + /** + * The method will be called when the application is signaled. + */ + public function handleSignal($signal); +} diff --git a/vendor-bundle/symfony/console/CommandLoader/CommandLoaderInterface.php b/vendor-bundle/symfony/console/CommandLoader/CommandLoaderInterface.php new file mode 100644 index 000000000..85873ecc0 --- /dev/null +++ b/vendor-bundle/symfony/console/CommandLoader/CommandLoaderInterface.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\CommandLoader; + +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Exception\CommandNotFoundException; +/** + * @author Robin Chalas + */ +interface CommandLoaderInterface +{ + /** + * Loads a command. + * + * @return Command + * + * @throws CommandNotFoundException + */ + public function get($name); + /** + * Checks if a command exists. + * + * @return bool + */ + public function has($name); + /** + * @return string[] All registered command names + */ + public function getNames(); +} diff --git a/vendor-bundle/symfony/console/CommandLoader/ContainerCommandLoader.php b/vendor-bundle/symfony/console/CommandLoader/ContainerCommandLoader.php new file mode 100644 index 000000000..92470d7e4 --- /dev/null +++ b/vendor-bundle/symfony/console/CommandLoader/ContainerCommandLoader.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\CommandLoader; + +use Phabel\Psr\Container\ContainerInterface; +use Phabel\Symfony\Component\Console\Exception\CommandNotFoundException; +/** + * Loads commands from a PSR-11 container. + * + * @author Robin Chalas + */ +class ContainerCommandLoader implements CommandLoaderInterface +{ + private $container; + private $commandMap; + /** + * @param array $commandMap An array with command names as keys and service ids as values + */ + public function __construct(ContainerInterface $container, array $commandMap) + { + $this->container = $container; + $this->commandMap = $commandMap; + } + /** + * {@inheritdoc} + */ + public function get($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!$this->has($name)) { + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); + } + return $this->container->get($this->commandMap[$name]); + } + /** + * {@inheritdoc} + */ + public function has($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]); + } + /** + * {@inheritdoc} + */ + public function getNames() + { + return \array_keys($this->commandMap); + } +} diff --git a/vendor-bundle/symfony/console/CommandLoader/FactoryCommandLoader.php b/vendor-bundle/symfony/console/CommandLoader/FactoryCommandLoader.php new file mode 100644 index 000000000..d6ed39262 --- /dev/null +++ b/vendor-bundle/symfony/console/CommandLoader/FactoryCommandLoader.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\CommandLoader; + +use Phabel\Symfony\Component\Console\Exception\CommandNotFoundException; +/** + * A simple command loader using factories to instantiate commands lazily. + * + * @author Maxime Steinhausser + */ +class FactoryCommandLoader implements CommandLoaderInterface +{ + private $factories; + /** + * @param callable[] $factories Indexed by command names + */ + public function __construct(array $factories) + { + $this->factories = $factories; + } + /** + * {@inheritdoc} + */ + public function has($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + return isset($this->factories[$name]); + } + /** + * {@inheritdoc} + */ + public function get($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!isset($this->factories[$name])) { + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); + } + $factory = $this->factories[$name]; + return $factory(); + } + /** + * {@inheritdoc} + */ + public function getNames() + { + return \array_keys($this->factories); + } +} diff --git a/vendor-bundle/symfony/console/ConsoleEvents.php b/vendor-bundle/symfony/console/ConsoleEvents.php new file mode 100644 index 000000000..75b8bd30d --- /dev/null +++ b/vendor-bundle/symfony/console/ConsoleEvents.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console; + +use Phabel\Symfony\Component\Console\Event\ConsoleCommandEvent; +use Phabel\Symfony\Component\Console\Event\ConsoleErrorEvent; +use Phabel\Symfony\Component\Console\Event\ConsoleSignalEvent; +use Phabel\Symfony\Component\Console\Event\ConsoleTerminateEvent; +/** + * Contains all events dispatched by an Application. + * + * @author Francesco Levorato + */ +final class ConsoleEvents +{ + /** + * The COMMAND event allows you to attach listeners before any command is + * executed by the console. It also allows you to modify the command, input and output + * before they are handed to the command. + * + * @Event("Symfony\Component\Console\Event\ConsoleCommandEvent") + */ + const COMMAND = 'console.command'; + /** + * The SIGNAL event allows you to perform some actions + * after the command execution was interrupted. + * + * @Event("Symfony\Component\Console\Event\ConsoleSignalEvent") + */ + const SIGNAL = 'console.signal'; + /** + * The TERMINATE event allows you to attach listeners after a command is + * executed by the console. + * + * @Event("Symfony\Component\Console\Event\ConsoleTerminateEvent") + */ + const TERMINATE = 'console.terminate'; + /** + * The ERROR event occurs when an uncaught exception or error appears. + * + * This event allows you to deal with the exception/error or + * to modify the thrown exception. + * + * @Event("Symfony\Component\Console\Event\ConsoleErrorEvent") + */ + const ERROR = 'console.error'; + /** + * Event aliases. + * + * These aliases can be consumed by RegisterListenersPass. + */ + const ALIASES = [ConsoleCommandEvent::class => self::COMMAND, ConsoleErrorEvent::class => self::ERROR, ConsoleSignalEvent::class => self::SIGNAL, ConsoleTerminateEvent::class => self::TERMINATE]; +} diff --git a/vendor-bundle/symfony/console/Cursor.php b/vendor-bundle/symfony/console/Cursor.php new file mode 100644 index 000000000..a3dc723c9 --- /dev/null +++ b/vendor-bundle/symfony/console/Cursor.php @@ -0,0 +1,241 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console; + +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Pierre du Plessis + */ +final class Cursor +{ + private $output; + private $input; + public function __construct(OutputInterface $output, $input = null) + { + $this->output = $output; + $this->input = isset($input) ? $input : (\defined('STDIN') ? \STDIN : \fopen('php://input', 'r+')); + } + public function moveUp($lines = 1) + { + if (!\is_int($lines)) { + if (!(\is_bool($lines) || \is_numeric($lines))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($lines) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($lines) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $lines = (int) $lines; + } + } + $this->output->write(\sprintf("\x1b[%dA", $lines)); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function moveDown($lines = 1) + { + if (!\is_int($lines)) { + if (!(\is_bool($lines) || \is_numeric($lines))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($lines) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($lines) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $lines = (int) $lines; + } + } + $this->output->write(\sprintf("\x1b[%dB", $lines)); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function moveRight($columns = 1) + { + if (!\is_int($columns)) { + if (!(\is_bool($columns) || \is_numeric($columns))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($columns) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($columns) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $columns = (int) $columns; + } + } + $this->output->write(\sprintf("\x1b[%dC", $columns)); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function moveLeft($columns = 1) + { + if (!\is_int($columns)) { + if (!(\is_bool($columns) || \is_numeric($columns))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($columns) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($columns) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $columns = (int) $columns; + } + } + $this->output->write(\sprintf("\x1b[%dD", $columns)); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function moveToColumn($column) + { + if (!\is_int($column)) { + if (!(\is_bool($column) || \is_numeric($column))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($column) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($column) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $column = (int) $column; + } + } + $this->output->write(\sprintf("\x1b[%dG", $column)); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function moveToPosition($column, $row) + { + if (!\is_int($column)) { + if (!(\is_bool($column) || \is_numeric($column))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($column) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($column) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $column = (int) $column; + } + } + if (!\is_int($row)) { + if (!(\is_bool($row) || \is_numeric($row))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($row) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($row) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $row = (int) $row; + } + } + $this->output->write(\sprintf("\x1b[%d;%dH", $row + 1, $column)); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function savePosition() + { + $this->output->write("\x1b7"); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function restorePosition() + { + $this->output->write("\x1b8"); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function hide() + { + $this->output->write("\x1b[?25l"); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function show() + { + $this->output->write("\x1b[?25h\x1b[?0c"); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Clears all the output from the current line. + */ + public function clearLine() + { + $this->output->write("\x1b[2K"); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Clears all the output from the current line after the current position. + */ + public function clearLineAfter() + { + $this->output->write("\x1b[K"); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Clears all the output from the cursors' current position to the end of the screen. + */ + public function clearOutput() + { + $this->output->write("\x1b[0J"); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Clears the entire screen. + */ + public function clearScreen() + { + $this->output->write("\x1b[2J"); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Returns the current cursor position as x,y coordinates. + */ + public function getCurrentPosition() + { + static $isTtySupported; + if (null === $isTtySupported && \function_exists('proc_open')) { + $isTtySupported = (bool) @\proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes); + } + if (!$isTtySupported) { + $phabelReturn = [1, 1]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $sttyMode = \shell_exec('stty -g'); + \shell_exec('stty -icanon -echo'); + @\fwrite($this->input, "\x1b[6n"); + $code = \trim(\fread($this->input, 1024)); + \shell_exec(\sprintf('stty %s', $sttyMode)); + \sscanf($code, "\x1b[%d;%dR", $row, $col); + $phabelReturn = [$col, $row]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/DependencyInjection/AddConsoleCommandPass.php b/vendor-bundle/symfony/console/DependencyInjection/AddConsoleCommandPass.php new file mode 100644 index 000000000..0b51020be --- /dev/null +++ b/vendor-bundle/symfony/console/DependencyInjection/AddConsoleCommandPass.php @@ -0,0 +1,146 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\DependencyInjection; + +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Command\LazyCommand; +use Phabel\Symfony\Component\Console\CommandLoader\ContainerCommandLoader; +use Phabel\Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Phabel\Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Phabel\Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; +use Phabel\Symfony\Component\DependencyInjection\ContainerBuilder; +use Phabel\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\DependencyInjection\Reference; +use Phabel\Symfony\Component\DependencyInjection\TypedReference; +/** + * Registers console commands. + * + * @author Grégoire Pineau + */ +class AddConsoleCommandPass implements CompilerPassInterface +{ + private $commandLoaderServiceId; + private $commandTag; + private $noPreloadTag; + private $privateTagName; + public function __construct($commandLoaderServiceId = 'console.command_loader', $commandTag = 'console.command', $noPreloadTag = 'container.no_preload', $privateTagName = 'container.private') + { + if (!\is_string($commandLoaderServiceId)) { + if (!(\is_string($commandLoaderServiceId) || \is_object($commandLoaderServiceId) && \method_exists($commandLoaderServiceId, '__toString') || (\is_bool($commandLoaderServiceId) || \is_numeric($commandLoaderServiceId)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($commandLoaderServiceId) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($commandLoaderServiceId) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $commandLoaderServiceId = (string) $commandLoaderServiceId; + } + } + if (!\is_string($commandTag)) { + if (!(\is_string($commandTag) || \is_object($commandTag) && \method_exists($commandTag, '__toString') || (\is_bool($commandTag) || \is_numeric($commandTag)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($commandTag) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($commandTag) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $commandTag = (string) $commandTag; + } + } + if (!\is_string($noPreloadTag)) { + if (!(\is_string($noPreloadTag) || \is_object($noPreloadTag) && \method_exists($noPreloadTag, '__toString') || (\is_bool($noPreloadTag) || \is_numeric($noPreloadTag)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($noPreloadTag) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($noPreloadTag) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $noPreloadTag = (string) $noPreloadTag; + } + } + if (!\is_string($privateTagName)) { + if (!(\is_string($privateTagName) || \is_object($privateTagName) && \method_exists($privateTagName, '__toString') || (\is_bool($privateTagName) || \is_numeric($privateTagName)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($privateTagName) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($privateTagName) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $privateTagName = (string) $privateTagName; + } + } + if (0 < \func_num_args()) { + trigger_deprecation('symfony/console', '5.3', 'Configuring "%s" is deprecated.', __CLASS__); + } + $this->commandLoaderServiceId = $commandLoaderServiceId; + $this->commandTag = $commandTag; + $this->noPreloadTag = $noPreloadTag; + $this->privateTagName = $privateTagName; + } + public function process(ContainerBuilder $container) + { + $commandServices = $container->findTaggedServiceIds($this->commandTag, \true); + $lazyCommandMap = []; + $lazyCommandRefs = []; + $serviceIds = []; + foreach ($commandServices as $id => $tags) { + $definition = $container->getDefinition($id); + $definition->addTag($this->noPreloadTag); + $class = $container->getParameterBag()->resolveValue($definition->getClass()); + if (isset($tags[0]['command'])) { + $aliases = $tags[0]['command']; + } else { + if (!($r = $container->getReflectionClass($class))) { + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + if (!$r->isSubclassOf(Command::class)) { + throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class)); + } + $aliases = $class::getDefaultName(); + } + $aliases = \explode('|', isset($aliases) ? $aliases : ''); + $commandName = \array_shift($aliases); + if ($isHidden = '' === $commandName) { + $commandName = \array_shift($aliases); + } + if (null === $commandName) { + if (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag($this->privateTagName)) { + $commandId = 'console.command.public_alias.' . $id; + $container->setAlias($commandId, $id)->setPublic(\true); + $id = $commandId; + } + $serviceIds[] = $id; + continue; + } + $description = isset($tags[0]['description']) ? $tags[0]['description'] : null; + unset($tags[0]); + $lazyCommandMap[$commandName] = $id; + $lazyCommandRefs[$id] = new TypedReference($id, $class); + foreach ($aliases as $alias) { + $lazyCommandMap[$alias] = $id; + } + foreach ($tags as $tag) { + if (isset($tag['command'])) { + $aliases[] = $tag['command']; + $lazyCommandMap[$tag['command']] = $id; + } + $description = isset($description) ? $description : (isset($tag['description']) ? $tag['description'] : null); + } + $definition->addMethodCall('setName', [$commandName]); + if ($aliases) { + $definition->addMethodCall('setAliases', [$aliases]); + } + if ($isHidden) { + $definition->addMethodCall('setHidden', [\true]); + } + if (!$description) { + if (!($r = $container->getReflectionClass($class))) { + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + if (!$r->isSubclassOf(Command::class)) { + throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, $this->commandTag, Command::class)); + } + $description = $class::getDefaultDescription(); + } + if ($description) { + $definition->addMethodCall('setDescription', [$description]); + $container->register('.' . $id . '.lazy', LazyCommand::class)->setArguments([$commandName, $aliases, $description, $isHidden, new ServiceClosureArgument($lazyCommandRefs[$id])]); + $lazyCommandRefs[$id] = new Reference('.' . $id . '.lazy'); + } + } + $container->register($this->commandLoaderServiceId, ContainerCommandLoader::class)->setPublic(\true)->addTag($this->noPreloadTag)->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]); + $container->setParameter('console.command.ids', $serviceIds); + } +} diff --git a/vendor-bundle/symfony/console/Descriptor/ApplicationDescription.php b/vendor-bundle/symfony/console/Descriptor/ApplicationDescription.php new file mode 100644 index 000000000..3bc5ecd51 --- /dev/null +++ b/vendor-bundle/symfony/console/Descriptor/ApplicationDescription.php @@ -0,0 +1,159 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Descriptor; + +use Phabel\Symfony\Component\Console\Application; +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Exception\CommandNotFoundException; +/** + * @author Jean-François Simon + * + * @internal + */ +class ApplicationDescription +{ + const GLOBAL_NAMESPACE = '_global'; + private $application; + private $namespace; + private $showHidden; + /** + * @var array + */ + private $namespaces; + /** + * @var Command[] + */ + private $commands; + /** + * @var Command[] + */ + private $aliases; + public function __construct(Application $application, $namespace = null, $showHidden = \false) + { + if (!\is_null($namespace)) { + if (!\is_string($namespace)) { + if (!(\is_string($namespace) || \is_object($namespace) && \method_exists($namespace, '__toString') || (\is_bool($namespace) || \is_numeric($namespace)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($namespace) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($namespace) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $namespace = (string) $namespace; + } + } + } + if (!\is_bool($showHidden)) { + if (!(\is_bool($showHidden) || \is_numeric($showHidden) || \is_string($showHidden))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($showHidden) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($showHidden) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $showHidden = (bool) $showHidden; + } + } + $this->application = $application; + $this->namespace = $namespace; + $this->showHidden = $showHidden; + } + public function getNamespaces() + { + if (null === $this->namespaces) { + $this->inspectApplication(); + } + $phabelReturn = $this->namespaces; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return Command[] + */ + public function getCommands() + { + if (null === $this->commands) { + $this->inspectApplication(); + } + $phabelReturn = $this->commands; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @throws CommandNotFoundException + */ + public function getCommand($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) { + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); + } + $phabelReturn = isset($this->commands[$name]) ? $this->commands[$name] : $this->aliases[$name]; + if (!$phabelReturn instanceof Command) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Command, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function inspectApplication() + { + $this->commands = []; + $this->namespaces = []; + $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null); + foreach ($this->sortCommands($all) as $namespace => $commands) { + $names = []; + /** @var Command $command */ + foreach ($commands as $name => $command) { + if (!$command->getName() || !$this->showHidden && $command->isHidden()) { + continue; + } + if ($command->getName() === $name) { + $this->commands[$name] = $command; + } else { + $this->aliases[$name] = $command; + } + $names[] = $name; + } + $this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names]; + } + } + private function sortCommands(array $commands) + { + $namespacedCommands = []; + $globalCommands = []; + $sortedCommands = []; + foreach ($commands as $name => $command) { + $key = $this->application->extractNamespace($name, 1); + if (\in_array($key, ['', self::GLOBAL_NAMESPACE], \true)) { + $globalCommands[$name] = $command; + } else { + $namespacedCommands[$key][$name] = $command; + } + } + if ($globalCommands) { + \ksort($globalCommands); + $sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands; + } + if ($namespacedCommands) { + \ksort($namespacedCommands); + foreach ($namespacedCommands as $key => $commandsSet) { + \ksort($commandsSet); + $sortedCommands[$key] = $commandsSet; + } + } + $phabelReturn = $sortedCommands; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Descriptor/Descriptor.php b/vendor-bundle/symfony/console/Descriptor/Descriptor.php new file mode 100644 index 000000000..99497aece --- /dev/null +++ b/vendor-bundle/symfony/console/Descriptor/Descriptor.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Descriptor; + +use Phabel\Symfony\Component\Console\Application; +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Input\InputArgument; +use Phabel\Symfony\Component\Console\Input\InputDefinition; +use Phabel\Symfony\Component\Console\Input\InputOption; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Jean-François Simon + * + * @internal + */ +abstract class Descriptor implements DescriptorInterface +{ + /** + * @var OutputInterface + */ + protected $output; + /** + * {@inheritdoc} + */ + public function describe(OutputInterface $output, $object, array $options = []) + { + if (!\is_object($object)) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($object) must be of type object, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($object) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $this->output = $output; + switch (\true) { + case $object instanceof InputArgument: + $this->describeInputArgument($object, $options); + break; + case $object instanceof InputOption: + $this->describeInputOption($object, $options); + break; + case $object instanceof InputDefinition: + $this->describeInputDefinition($object, $options); + break; + case $object instanceof Command: + $this->describeCommand($object, $options); + break; + case $object instanceof Application: + $this->describeApplication($object, $options); + break; + default: + throw new InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', \get_debug_type($object))); + } + } + /** + * Writes content to output. + */ + protected function write($content, $decorated = \false) + { + if (!\is_string($content)) { + if (!(\is_string($content) || \is_object($content) && \method_exists($content, '__toString') || (\is_bool($content) || \is_numeric($content)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($content) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($content) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $content = (string) $content; + } + } + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($decorated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + $this->output->write($content, \false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW); + } + /** + * Describes an InputArgument instance. + */ + protected abstract function describeInputArgument(InputArgument $argument, array $options = []); + /** + * Describes an InputOption instance. + */ + protected abstract function describeInputOption(InputOption $option, array $options = []); + /** + * Describes an InputDefinition instance. + */ + protected abstract function describeInputDefinition(InputDefinition $definition, array $options = []); + /** + * Describes a Command instance. + */ + protected abstract function describeCommand(Command $command, array $options = []); + /** + * Describes an Application instance. + */ + protected abstract function describeApplication(Application $application, array $options = []); +} diff --git a/vendor-bundle/symfony/console/Descriptor/DescriptorInterface.php b/vendor-bundle/symfony/console/Descriptor/DescriptorInterface.php new file mode 100644 index 000000000..d7026d89f --- /dev/null +++ b/vendor-bundle/symfony/console/Descriptor/DescriptorInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Descriptor; + +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * Descriptor interface. + * + * @author Jean-François Simon + */ +interface DescriptorInterface +{ + public function describe(OutputInterface $output, $object, array $options = []); +} diff --git a/vendor-bundle/symfony/console/Descriptor/JsonDescriptor.php b/vendor-bundle/symfony/console/Descriptor/JsonDescriptor.php new file mode 100644 index 000000000..eb51541a4 --- /dev/null +++ b/vendor-bundle/symfony/console/Descriptor/JsonDescriptor.php @@ -0,0 +1,157 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Descriptor; + +use Phabel\Symfony\Component\Console\Application; +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Input\InputArgument; +use Phabel\Symfony\Component\Console\Input\InputDefinition; +use Phabel\Symfony\Component\Console\Input\InputOption; +/** + * JSON descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class JsonDescriptor extends Descriptor +{ + /** + * {@inheritdoc} + */ + protected function describeInputArgument(InputArgument $argument, array $options = []) + { + $this->writeData($this->getInputArgumentData($argument), $options); + } + /** + * {@inheritdoc} + */ + protected function describeInputOption(InputOption $option, array $options = []) + { + $this->writeData($this->getInputOptionData($option), $options); + if ($option->isNegatable()) { + $this->writeData($this->getInputOptionData($option, \true), $options); + } + } + /** + * {@inheritdoc} + */ + protected function describeInputDefinition(InputDefinition $definition, array $options = []) + { + $this->writeData($this->getInputDefinitionData($definition), $options); + } + /** + * {@inheritdoc} + */ + protected function describeCommand(Command $command, array $options = []) + { + $this->writeData($this->getCommandData($command, isset($options['short']) ? $options['short'] : \false), $options); + } + /** + * {@inheritdoc} + */ + protected function describeApplication(Application $application, array $options = []) + { + $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null; + $description = new ApplicationDescription($application, $describedNamespace, \true); + $commands = []; + foreach ($description->getCommands() as $command) { + $commands[] = $this->getCommandData($command, isset($options['short']) ? $options['short'] : \false); + } + $data = []; + if ('UNKNOWN' !== $application->getName()) { + $data['application']['name'] = $application->getName(); + if ('UNKNOWN' !== $application->getVersion()) { + $data['application']['version'] = $application->getVersion(); + } + } + $data['commands'] = $commands; + if ($describedNamespace) { + $data['namespace'] = $describedNamespace; + } else { + $data['namespaces'] = \array_values($description->getNamespaces()); + } + $this->writeData($data, $options); + } + /** + * Writes data as json. + */ + private function writeData(array $data, array $options) + { + $flags = isset($options['json_encoding']) ? $options['json_encoding'] : 0; + $this->write(\json_encode($data, $flags)); + } + private function getInputArgumentData(InputArgument $argument) + { + $phabelReturn = ['name' => $argument->getName(), 'is_required' => $argument->isRequired(), 'is_array' => $argument->isArray(), 'description' => \preg_replace('/\\s*[\\r\\n]\\s*/', ' ', $argument->getDescription()), 'default' => \INF === $argument->getDefault() ? 'INF' : $argument->getDefault()]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function getInputOptionData(InputOption $option, $negated = \false) + { + if (!\is_bool($negated)) { + if (!(\is_bool($negated) || \is_numeric($negated) || \is_string($negated))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($negated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($negated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $negated = (bool) $negated; + } + } + $phabelReturn = $negated ? ['name' => '--no-' . $option->getName(), 'shortcut' => '', 'accept_value' => \false, 'is_value_required' => \false, 'is_multiple' => \false, 'description' => 'Negate the "--' . $option->getName() . '" option', 'default' => \false] : ['name' => '--' . $option->getName(), 'shortcut' => $option->getShortcut() ? '-' . \str_replace('|', '|-', $option->getShortcut()) : '', 'accept_value' => $option->acceptValue(), 'is_value_required' => $option->isValueRequired(), 'is_multiple' => $option->isArray(), 'description' => \preg_replace('/\\s*[\\r\\n]\\s*/', ' ', $option->getDescription()), 'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault()]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function getInputDefinitionData(InputDefinition $definition) + { + $inputArguments = []; + foreach ($definition->getArguments() as $name => $argument) { + $inputArguments[$name] = $this->getInputArgumentData($argument); + } + $inputOptions = []; + foreach ($definition->getOptions() as $name => $option) { + $inputOptions[$name] = $this->getInputOptionData($option); + if ($option->isNegatable()) { + $inputOptions['no-' . $name] = $this->getInputOptionData($option, \true); + } + } + $phabelReturn = ['arguments' => $inputArguments, 'options' => $inputOptions]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function getCommandData(Command $command, $short = \false) + { + if (!\is_bool($short)) { + if (!(\is_bool($short) || \is_numeric($short) || \is_string($short))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($short) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($short) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $short = (bool) $short; + } + } + $data = ['name' => $command->getName(), 'description' => $command->getDescription()]; + if ($short) { + $data += ['usage' => $command->getAliases()]; + } else { + $command->mergeApplicationDefinition(\false); + $data += ['usage' => \array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()), 'help' => $command->getProcessedHelp(), 'definition' => $this->getInputDefinitionData($command->getDefinition())]; + } + $data['hidden'] = $command->isHidden(); + $phabelReturn = $data; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Descriptor/MarkdownDescriptor.php b/vendor-bundle/symfony/console/Descriptor/MarkdownDescriptor.php new file mode 100644 index 000000000..0ce390a2c --- /dev/null +++ b/vendor-bundle/symfony/console/Descriptor/MarkdownDescriptor.php @@ -0,0 +1,210 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Descriptor; + +use Phabel\Symfony\Component\Console\Application; +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Helper\Helper; +use Phabel\Symfony\Component\Console\Input\InputArgument; +use Phabel\Symfony\Component\Console\Input\InputDefinition; +use Phabel\Symfony\Component\Console\Input\InputOption; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * Markdown descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class MarkdownDescriptor extends Descriptor +{ + /** + * {@inheritdoc} + */ + public function describe(OutputInterface $output, $object, array $options = []) + { + if (!\is_object($object)) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($object) must be of type object, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($object) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $decorated = $output->isDecorated(); + $output->setDecorated(\false); + parent::describe($output, $object, $options); + $output->setDecorated($decorated); + } + /** + * {@inheritdoc} + */ + protected function write($content, $decorated = \true) + { + if (!\is_string($content)) { + if (!(\is_string($content) || \is_object($content) && \method_exists($content, '__toString') || (\is_bool($content) || \is_numeric($content)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($content) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($content) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $content = (string) $content; + } + } + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($decorated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + parent::write($content, $decorated); + } + /** + * {@inheritdoc} + */ + protected function describeInputArgument(InputArgument $argument, array $options = []) + { + $this->write('#### `' . ($argument->getName() ?: '') . "`\n\n" . ($argument->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n", $argument->getDescription()) . "\n\n" : '') . '* Is required: ' . ($argument->isRequired() ? 'yes' : 'no') . ' +* Is array: ' . ($argument->isArray() ? 'yes' : 'no') . ' +* Default: `' . \str_replace("\n", '', \var_export($argument->getDefault(), \true)) . '`'); + } + /** + * {@inheritdoc} + */ + protected function describeInputOption(InputOption $option, array $options = []) + { + $name = '--' . $option->getName(); + if ($option->isNegatable()) { + $name .= '|--no-' . $option->getName(); + } + if ($option->getShortcut()) { + $name .= '|-' . \str_replace('|', '|-', $option->getShortcut()) . ''; + } + $this->write('#### `' . $name . '` + +' . ($option->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n", $option->getDescription()) . "\n\n" : '') . '* Accept value: ' . ($option->acceptValue() ? 'yes' : 'no') . ' +* Is value required: ' . ($option->isValueRequired() ? 'yes' : 'no') . ' +* Is multiple: ' . ($option->isArray() ? 'yes' : 'no') . ' +* Is negatable: ' . ($option->isNegatable() ? 'yes' : 'no') . ' +* Default: `' . \str_replace("\n", '', \var_export($option->getDefault(), \true)) . '`'); + } + /** + * {@inheritdoc} + */ + protected function describeInputDefinition(InputDefinition $definition, array $options = []) + { + if ($showArguments = \count($definition->getArguments()) > 0) { + $this->write('### Arguments'); + foreach ($definition->getArguments() as $argument) { + $this->write("\n\n"); + if (null !== ($describeInputArgument = $this->describeInputArgument($argument))) { + $this->write($describeInputArgument); + } + } + } + if (\count($definition->getOptions()) > 0) { + if ($showArguments) { + $this->write("\n\n"); + } + $this->write('### Options'); + foreach ($definition->getOptions() as $option) { + $this->write("\n\n"); + if (null !== ($describeInputOption = $this->describeInputOption($option))) { + $this->write($describeInputOption); + } + } + } + } + /** + * {@inheritdoc} + */ + protected function describeCommand(Command $command, array $options = []) + { + if (isset($options['short']) ? $options['short'] : \false) { + $this->write('`' . $command->getName() . "`\n" . \str_repeat('-', Helper::width($command->getName()) + 2) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . '### Usage + +' . \array_reduce($command->getAliases(), function ($carry, $usage) { + return $carry . '* `' . $usage . '` +'; + })); + return; + } + $command->mergeApplicationDefinition(\false); + $this->write('`' . $command->getName() . "`\n" . \str_repeat('-', Helper::width($command->getName()) + 2) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . '### Usage + +' . \array_reduce(\array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) { + return $carry . '* `' . $usage . '` +'; + })); + if ($help = $command->getProcessedHelp()) { + $this->write("\n"); + $this->write($help); + } + $definition = $command->getDefinition(); + if ($definition->getOptions() || $definition->getArguments()) { + $this->write("\n\n"); + $this->describeInputDefinition($definition); + } + } + /** + * {@inheritdoc} + */ + protected function describeApplication(Application $application, array $options = []) + { + $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null; + $description = new ApplicationDescription($application, $describedNamespace); + $title = $this->getApplicationTitle($application); + $this->write($title . "\n" . \str_repeat('=', Helper::width($title))); + foreach ($description->getNamespaces() as $namespace) { + if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { + $this->write("\n\n"); + $this->write('**' . $namespace['id'] . ':**'); + } + $this->write("\n\n"); + $this->write(\implode("\n", \array_map(function ($commandName) use($description) { + return \sprintf('* [`%s`](#%s)', $commandName, \str_replace(':', '', $description->getCommand($commandName)->getName())); + }, $namespace['commands']))); + } + foreach ($description->getCommands() as $command) { + $this->write("\n\n"); + if (null !== ($describeCommand = $this->describeCommand($command, $options))) { + $this->write($describeCommand); + } + } + } + private function getApplicationTitle(Application $application) + { + if ('UNKNOWN' !== $application->getName()) { + if ('UNKNOWN' !== $application->getVersion()) { + $phabelReturn = \sprintf('%s %s', $application->getName(), $application->getVersion()); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = $application->getName(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = 'Console Tool'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Descriptor/TextDescriptor.php b/vendor-bundle/symfony/console/Descriptor/TextDescriptor.php new file mode 100644 index 000000000..8148a494e --- /dev/null +++ b/vendor-bundle/symfony/console/Descriptor/TextDescriptor.php @@ -0,0 +1,340 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Descriptor; + +use Phabel\Symfony\Component\Console\Application; +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Formatter\OutputFormatter; +use Phabel\Symfony\Component\Console\Helper\Helper; +use Phabel\Symfony\Component\Console\Input\InputArgument; +use Phabel\Symfony\Component\Console\Input\InputDefinition; +use Phabel\Symfony\Component\Console\Input\InputOption; +/** + * Text descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class TextDescriptor extends Descriptor +{ + /** + * {@inheritdoc} + */ + protected function describeInputArgument(InputArgument $argument, array $options = []) + { + if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) { + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); + } else { + $default = ''; + } + $totalWidth = isset($options['total_width']) ? $options['total_width'] : Helper::width($argument->getName()); + $spacingWidth = $totalWidth - \strlen($argument->getName()); + $this->writeText(\sprintf( + ' %s %s%s%s', + $argument->getName(), + \str_repeat(' ', $spacingWidth), + // + 4 = 2 spaces before , 2 spaces after + \preg_replace('/\\s*[\\r\\n]\\s*/', "\n" . \str_repeat(' ', $totalWidth + 4), $argument->getDescription()), + $default + ), $options); + } + /** + * {@inheritdoc} + */ + protected function describeInputOption(InputOption $option, array $options = []) + { + if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) { + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); + } else { + $default = ''; + } + $value = ''; + if ($option->acceptValue()) { + $value = '=' . \strtoupper($option->getName()); + if ($option->isValueOptional()) { + $value = '[' . $value . ']'; + } + } + $totalWidth = isset($options['total_width']) ? $options['total_width'] : $this->calculateTotalWidthForOptions([$option]); + $synopsis = \sprintf('%s%s', $option->getShortcut() ? \sprintf('-%s, ', $option->getShortcut()) : ' ', \sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value)); + $spacingWidth = $totalWidth - Helper::width($synopsis); + $this->writeText(\sprintf( + ' %s %s%s%s%s', + $synopsis, + \str_repeat(' ', $spacingWidth), + // + 4 = 2 spaces before , 2 spaces after + \preg_replace('/\\s*[\\r\\n]\\s*/', "\n" . \str_repeat(' ', $totalWidth + 4), $option->getDescription()), + $default, + $option->isArray() ? ' (multiple values allowed)' : '' + ), $options); + } + /** + * {@inheritdoc} + */ + protected function describeInputDefinition(InputDefinition $definition, array $options = []) + { + $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions()); + foreach ($definition->getArguments() as $argument) { + $totalWidth = \max($totalWidth, Helper::width($argument->getName())); + } + if ($definition->getArguments()) { + $this->writeText('Arguments:', $options); + $this->writeText("\n"); + foreach ($definition->getArguments() as $argument) { + $this->describeInputArgument($argument, \array_merge($options, ['total_width' => $totalWidth])); + $this->writeText("\n"); + } + } + if ($definition->getArguments() && $definition->getOptions()) { + $this->writeText("\n"); + } + if ($definition->getOptions()) { + $laterOptions = []; + $this->writeText('Options:', $options); + foreach ($definition->getOptions() as $option) { + if (\strlen(NULL !== ($phabel_30ed5abe19edb800 = $option->getShortcut()) ? $phabel_30ed5abe19edb800 : '') > 1) { + $laterOptions[] = $option; + continue; + } + $this->writeText("\n"); + $this->describeInputOption($option, \array_merge($options, ['total_width' => $totalWidth])); + } + foreach ($laterOptions as $option) { + $this->writeText("\n"); + $this->describeInputOption($option, \array_merge($options, ['total_width' => $totalWidth])); + } + } + } + /** + * {@inheritdoc} + */ + protected function describeCommand(Command $command, array $options = []) + { + $command->mergeApplicationDefinition(\false); + if ($description = $command->getDescription()) { + $this->writeText('Description:', $options); + $this->writeText("\n"); + $this->writeText(' ' . $description); + $this->writeText("\n\n"); + } + $this->writeText('Usage:', $options); + foreach (\array_merge([$command->getSynopsis(\true)], $command->getAliases(), $command->getUsages()) as $usage) { + $this->writeText("\n"); + $this->writeText(' ' . OutputFormatter::escape($usage), $options); + } + $this->writeText("\n"); + $definition = $command->getDefinition(); + if ($definition->getOptions() || $definition->getArguments()) { + $this->writeText("\n"); + $this->describeInputDefinition($definition, $options); + $this->writeText("\n"); + } + $help = $command->getProcessedHelp(); + if ($help && $help !== $description) { + $this->writeText("\n"); + $this->writeText('Help:', $options); + $this->writeText("\n"); + $this->writeText(' ' . \str_replace("\n", "\n ", $help), $options); + $this->writeText("\n"); + } + } + /** + * {@inheritdoc} + */ + protected function describeApplication(Application $application, array $options = []) + { + $describedNamespace = isset($options['namespace']) ? $options['namespace'] : null; + $description = new ApplicationDescription($application, $describedNamespace); + if (isset($options['raw_text']) && $options['raw_text']) { + $width = $this->getColumnWidth($description->getCommands()); + foreach ($description->getCommands() as $command) { + $this->writeText(\sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); + $this->writeText("\n"); + } + } else { + if ('' != ($help = $application->getHelp())) { + $this->writeText("{$help}\n\n", $options); + } + $this->writeText("Usage:\n", $options); + $this->writeText(" command [options] [arguments]\n\n", $options); + $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options); + $this->writeText("\n"); + $this->writeText("\n"); + $commands = $description->getCommands(); + $namespaces = $description->getNamespaces(); + if ($describedNamespace && $namespaces) { + // make sure all alias commands are included when describing a specific namespace + $describedNamespaceInfo = \reset($namespaces); + foreach ($describedNamespaceInfo['commands'] as $name) { + $commands[$name] = $description->getCommand($name); + } + } + // calculate max. width based on available commands per namespace + $width = $this->getColumnWidth(\array_merge(...\array_values(\array_map(function ($namespace) use($commands) { + return \array_intersect($namespace['commands'], \array_keys($commands)); + }, \array_values($namespaces))))); + if ($describedNamespace) { + $this->writeText(\sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); + } else { + $this->writeText('Available commands:', $options); + } + foreach ($namespaces as $namespace) { + $namespace['commands'] = \array_filter($namespace['commands'], function ($name) use($commands) { + return isset($commands[$name]); + }); + if (!$namespace['commands']) { + continue; + } + if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { + $this->writeText("\n"); + $this->writeText(' ' . $namespace['id'] . '', $options); + } + foreach ($namespace['commands'] as $name) { + $this->writeText("\n"); + $spacingWidth = $width - Helper::width($name); + $command = $commands[$name]; + $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : ''; + $this->writeText(\sprintf(' %s%s%s', $name, \str_repeat(' ', $spacingWidth), $commandAliases . $command->getDescription()), $options); + } + } + $this->writeText("\n"); + } + } + /** + * {@inheritdoc} + */ + private function writeText($content, array $options = []) + { + if (!\is_string($content)) { + if (!(\is_string($content) || \is_object($content) && \method_exists($content, '__toString') || (\is_bool($content) || \is_numeric($content)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($content) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($content) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $content = (string) $content; + } + } + $this->write(isset($options['raw_text']) && $options['raw_text'] ? \strip_tags($content) : $content, isset($options['raw_output']) ? !$options['raw_output'] : \true); + } + /** + * Formats command aliases to show them in the command description. + */ + private function getCommandAliasesText(Command $command) + { + $text = ''; + $aliases = $command->getAliases(); + if ($aliases) { + $text = '[' . \implode('|', $aliases) . '] '; + } + $phabelReturn = $text; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Formats input option/argument default value. + * + * @param mixed $default + */ + private function formatDefaultValue($default) + { + if (\INF === $default) { + $phabelReturn = 'INF'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (\is_string($default)) { + $default = OutputFormatter::escape($default); + } elseif (\is_array($default)) { + foreach ($default as $key => $value) { + if (\is_string($value)) { + $default[$key] = OutputFormatter::escape($value); + } + } + } + $phabelReturn = \str_replace('\\\\', '\\', \json_encode($default, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @param array $commands + */ + private function getColumnWidth(array $commands) + { + $widths = []; + foreach ($commands as $command) { + if ($command instanceof Command) { + $widths[] = Helper::width($command->getName()); + foreach ($command->getAliases() as $alias) { + $widths[] = Helper::width($alias); + } + } else { + $widths[] = Helper::width($command); + } + } + $phabelReturn = $widths ? \max($widths) + 2 : 0; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @param InputOption[] $options + */ + private function calculateTotalWidthForOptions(array $options) + { + $totalWidth = 0; + foreach ($options as $option) { + // "-" + shortcut + ", --" + name + $nameLength = 1 + \max(Helper::width($option->getShortcut()), 1) + 4 + Helper::width($option->getName()); + if ($option->isNegatable()) { + $nameLength += 6 + Helper::width($option->getName()); + // |--no- + name + } elseif ($option->acceptValue()) { + $valueLength = 1 + Helper::width($option->getName()); + // = + value + $valueLength += $option->isValueOptional() ? 2 : 0; + // [ + ] + $nameLength += $valueLength; + } + $totalWidth = \max($totalWidth, $nameLength); + } + $phabelReturn = $totalWidth; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Descriptor/XmlDescriptor.php b/vendor-bundle/symfony/console/Descriptor/XmlDescriptor.php new file mode 100644 index 000000000..78c9c8011 --- /dev/null +++ b/vendor-bundle/symfony/console/Descriptor/XmlDescriptor.php @@ -0,0 +1,249 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Descriptor; + +use Phabel\Symfony\Component\Console\Application; +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Input\InputArgument; +use Phabel\Symfony\Component\Console\Input\InputDefinition; +use Phabel\Symfony\Component\Console\Input\InputOption; +/** + * XML descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class XmlDescriptor extends Descriptor +{ + public function getInputDefinitionDocument(InputDefinition $definition) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($definitionXML = $dom->createElement('definition')); + $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments')); + foreach ($definition->getArguments() as $argument) { + $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument)); + } + $definitionXML->appendChild($optionsXML = $dom->createElement('options')); + foreach ($definition->getOptions() as $option) { + $this->appendDocument($optionsXML, $this->getInputOptionDocument($option)); + } + $phabelReturn = $dom; + if (!$phabelReturn instanceof \DOMDocument) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type DOMDocument, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getCommandDocument(Command $command, $short = \false) + { + if (!\is_bool($short)) { + if (!(\is_bool($short) || \is_numeric($short) || \is_string($short))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($short) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($short) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $short = (bool) $short; + } + } + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($commandXML = $dom->createElement('command')); + $commandXML->setAttribute('id', $command->getName()); + $commandXML->setAttribute('name', $command->getName()); + $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0); + $commandXML->appendChild($usagesXML = $dom->createElement('usages')); + $commandXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode(\str_replace("\n", "\n ", $command->getDescription()))); + if ($short) { + foreach ($command->getAliases() as $usage) { + $usagesXML->appendChild($dom->createElement('usage', $usage)); + } + } else { + $command->mergeApplicationDefinition(\false); + foreach (\array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) { + $usagesXML->appendChild($dom->createElement('usage', $usage)); + } + $commandXML->appendChild($helpXML = $dom->createElement('help')); + $helpXML->appendChild($dom->createTextNode(\str_replace("\n", "\n ", $command->getProcessedHelp()))); + $definitionXML = $this->getInputDefinitionDocument($command->getDefinition()); + $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0)); + } + $phabelReturn = $dom; + if (!$phabelReturn instanceof \DOMDocument) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type DOMDocument, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getApplicationDocument(Application $application, $namespace = null, $short = \false) + { + if (!\is_null($namespace)) { + if (!\is_string($namespace)) { + if (!(\is_string($namespace) || \is_object($namespace) && \method_exists($namespace, '__toString') || (\is_bool($namespace) || \is_numeric($namespace)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($namespace) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($namespace) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $namespace = (string) $namespace; + } + } + } + if (!\is_bool($short)) { + if (!(\is_bool($short) || \is_numeric($short) || \is_string($short))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($short) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($short) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $short = (bool) $short; + } + } + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($rootXml = $dom->createElement('symfony')); + if ('UNKNOWN' !== $application->getName()) { + $rootXml->setAttribute('name', $application->getName()); + if ('UNKNOWN' !== $application->getVersion()) { + $rootXml->setAttribute('version', $application->getVersion()); + } + } + $rootXml->appendChild($commandsXML = $dom->createElement('commands')); + $description = new ApplicationDescription($application, $namespace, \true); + if ($namespace) { + $commandsXML->setAttribute('namespace', $namespace); + } + foreach ($description->getCommands() as $command) { + $this->appendDocument($commandsXML, $this->getCommandDocument($command, $short)); + } + if (!$namespace) { + $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces')); + foreach ($description->getNamespaces() as $namespaceDescription) { + $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace')); + $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']); + foreach ($namespaceDescription['commands'] as $name) { + $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command')); + $commandXML->appendChild($dom->createTextNode($name)); + } + } + } + $phabelReturn = $dom; + if (!$phabelReturn instanceof \DOMDocument) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type DOMDocument, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + protected function describeInputArgument(InputArgument $argument, array $options = []) + { + $this->writeDocument($this->getInputArgumentDocument($argument)); + } + /** + * {@inheritdoc} + */ + protected function describeInputOption(InputOption $option, array $options = []) + { + $this->writeDocument($this->getInputOptionDocument($option)); + } + /** + * {@inheritdoc} + */ + protected function describeInputDefinition(InputDefinition $definition, array $options = []) + { + $this->writeDocument($this->getInputDefinitionDocument($definition)); + } + /** + * {@inheritdoc} + */ + protected function describeCommand(Command $command, array $options = []) + { + $this->writeDocument($this->getCommandDocument($command, isset($options['short']) ? $options['short'] : \false)); + } + /** + * {@inheritdoc} + */ + protected function describeApplication(Application $application, array $options = []) + { + $this->writeDocument($this->getApplicationDocument($application, isset($options['namespace']) ? $options['namespace'] : null, isset($options['short']) ? $options['short'] : \false)); + } + /** + * Appends document children to parent node. + */ + private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent) + { + foreach ($importedParent->childNodes as $childNode) { + $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, \true)); + } + } + /** + * Writes DOM document. + */ + private function writeDocument(\DOMDocument $dom) + { + $dom->formatOutput = \true; + $this->write($dom->saveXML()); + } + private function getInputArgumentDocument(InputArgument $argument) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($objectXML = $dom->createElement('argument')); + $objectXML->setAttribute('name', $argument->getName()); + $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0); + $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0); + $objectXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode($argument->getDescription())); + $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); + $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [\var_export($argument->getDefault(), \true)] : ($argument->getDefault() ? [$argument->getDefault()] : [])); + foreach ($defaults as $default) { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); + } + $phabelReturn = $dom; + if (!$phabelReturn instanceof \DOMDocument) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type DOMDocument, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function getInputOptionDocument(InputOption $option) + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($objectXML = $dom->createElement('option')); + $objectXML->setAttribute('name', '--' . $option->getName()); + $pos = \strpos(NULL !== ($phabel_aaa4c7c842e5280f = $option->getShortcut()) ? $phabel_aaa4c7c842e5280f : '', '|'); + if (\false !== $pos) { + $objectXML->setAttribute('shortcut', '-' . \substr($option->getShortcut(), 0, $pos)); + $objectXML->setAttribute('shortcuts', '-' . \str_replace('|', '|-', $option->getShortcut())); + } else { + $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-' . $option->getShortcut() : ''); + } + $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0); + $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0); + $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0); + $objectXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode($option->getDescription())); + if ($option->acceptValue()) { + $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [\var_export($option->getDefault(), \true)] : ($option->getDefault() ? [$option->getDefault()] : [])); + $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); + if (!empty($defaults)) { + foreach ($defaults as $default) { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); + } + } + } + if ($option->isNegatable()) { + $dom->appendChild($objectXML = $dom->createElement('option')); + $objectXML->setAttribute('name', '--no-' . $option->getName()); + $objectXML->setAttribute('shortcut', ''); + $objectXML->setAttribute('accept_value', 0); + $objectXML->setAttribute('is_value_required', 0); + $objectXML->setAttribute('is_multiple', 0); + $objectXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode('Negate the "--' . $option->getName() . '" option')); + } + $phabelReturn = $dom; + if (!$phabelReturn instanceof \DOMDocument) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type DOMDocument, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Event/ConsoleCommandEvent.php b/vendor-bundle/symfony/console/Event/ConsoleCommandEvent.php new file mode 100644 index 000000000..00123c19e --- /dev/null +++ b/vendor-bundle/symfony/console/Event/ConsoleCommandEvent.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Event; + +/** + * Allows to do things before the command is executed, like skipping the command or changing the input. + * + * @author Fabien Potencier + */ +final class ConsoleCommandEvent extends ConsoleEvent +{ + /** + * The return code for skipped commands, this will also be passed into the terminate event. + */ + const RETURN_CODE_DISABLED = 113; + /** + * Indicates if the command should be run or skipped. + */ + private $commandShouldRun = \true; + /** + * Disables the command, so it won't be run. + */ + public function disableCommand() + { + $phabelReturn = $this->commandShouldRun = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function enableCommand() + { + $phabelReturn = $this->commandShouldRun = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Returns true if the command is runnable, false otherwise. + */ + public function commandShouldRun() + { + $phabelReturn = $this->commandShouldRun; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Event/ConsoleErrorEvent.php b/vendor-bundle/symfony/console/Event/ConsoleErrorEvent.php new file mode 100644 index 000000000..7d8a36bf0 --- /dev/null +++ b/vendor-bundle/symfony/console/Event/ConsoleErrorEvent.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Event; + +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * Allows to handle throwables thrown while running a command. + * + * @author Wouter de Jong + */ +final class ConsoleErrorEvent extends ConsoleEvent +{ + private $error; + private $exitCode; + public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, Command $command = null) + { + parent::__construct($command, $input, $output); + $this->error = $error; + } + public function getError() + { + $phabelReturn = $this->error; + if (!($phabelReturn instanceof \Exception || $phabelReturn instanceof \Error)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Throwable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function setError(\Throwable $error) + { + $this->error = $error; + } + public function setExitCode($exitCode) + { + if (!\is_int($exitCode)) { + if (!(\is_bool($exitCode) || \is_numeric($exitCode))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($exitCode) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($exitCode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $exitCode = (int) $exitCode; + } + } + $this->exitCode = $exitCode; + $r = new \ReflectionProperty($this->error, 'code'); + $r->setAccessible(\true); + $r->setValue($this->error, $this->exitCode); + } + public function getExitCode() + { + $phabelReturn = isset($this->exitCode) ? $this->exitCode : (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Event/ConsoleEvent.php b/vendor-bundle/symfony/console/Event/ConsoleEvent.php new file mode 100644 index 000000000..784dfbdf6 --- /dev/null +++ b/vendor-bundle/symfony/console/Event/ConsoleEvent.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Event; + +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +use Phabel\Symfony\Contracts\EventDispatcher\Event; +/** + * Allows to inspect input and output of a command. + * + * @author Francesco Levorato + */ +class ConsoleEvent extends Event +{ + protected $command; + private $input; + private $output; + public function __construct(Command $command = null, InputInterface $input, OutputInterface $output) + { + $this->command = $command; + $this->input = $input; + $this->output = $output; + } + /** + * Gets the command that is executed. + * + * @return Command|null A Command instance + */ + public function getCommand() + { + return $this->command; + } + /** + * Gets the input instance. + * + * @return InputInterface An InputInterface instance + */ + public function getInput() + { + return $this->input; + } + /** + * Gets the output instance. + * + * @return OutputInterface An OutputInterface instance + */ + public function getOutput() + { + return $this->output; + } +} diff --git a/vendor-bundle/symfony/console/Event/ConsoleSignalEvent.php b/vendor-bundle/symfony/console/Event/ConsoleSignalEvent.php new file mode 100644 index 000000000..9eac4e712 --- /dev/null +++ b/vendor-bundle/symfony/console/Event/ConsoleSignalEvent.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Event; + +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * @author marie + */ +final class ConsoleSignalEvent extends ConsoleEvent +{ + private $handlingSignal; + public function __construct(Command $command, InputInterface $input, OutputInterface $output, $handlingSignal) + { + if (!\is_int($handlingSignal)) { + if (!(\is_bool($handlingSignal) || \is_numeric($handlingSignal))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($handlingSignal) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($handlingSignal) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $handlingSignal = (int) $handlingSignal; + } + } + parent::__construct($command, $input, $output); + $this->handlingSignal = $handlingSignal; + } + public function getHandlingSignal() + { + $phabelReturn = $this->handlingSignal; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Event/ConsoleTerminateEvent.php b/vendor-bundle/symfony/console/Event/ConsoleTerminateEvent.php new file mode 100644 index 000000000..5d113382b --- /dev/null +++ b/vendor-bundle/symfony/console/Event/ConsoleTerminateEvent.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Event; + +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * Allows to manipulate the exit code of a command after its execution. + * + * @author Francesco Levorato + */ +final class ConsoleTerminateEvent extends ConsoleEvent +{ + private $exitCode; + public function __construct(Command $command, InputInterface $input, OutputInterface $output, $exitCode) + { + if (!\is_int($exitCode)) { + if (!(\is_bool($exitCode) || \is_numeric($exitCode))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($exitCode) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($exitCode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $exitCode = (int) $exitCode; + } + } + parent::__construct($command, $input, $output); + $this->setExitCode($exitCode); + } + public function setExitCode($exitCode) + { + if (!\is_int($exitCode)) { + if (!(\is_bool($exitCode) || \is_numeric($exitCode))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($exitCode) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($exitCode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $exitCode = (int) $exitCode; + } + } + $this->exitCode = $exitCode; + } + public function getExitCode() + { + $phabelReturn = $this->exitCode; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/EventListener/ErrorListener.php b/vendor-bundle/symfony/console/EventListener/ErrorListener.php new file mode 100644 index 000000000..9c1798304 --- /dev/null +++ b/vendor-bundle/symfony/console/EventListener/ErrorListener.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\EventListener; + +use Phabel\Psr\Log\LoggerInterface; +use Phabel\Symfony\Component\Console\ConsoleEvents; +use Phabel\Symfony\Component\Console\Event\ConsoleErrorEvent; +use Phabel\Symfony\Component\Console\Event\ConsoleEvent; +use Phabel\Symfony\Component\Console\Event\ConsoleTerminateEvent; +use Phabel\Symfony\Component\EventDispatcher\EventSubscriberInterface; +/** + * @author James Halsall + * @author Robin Chalas + */ +class ErrorListener implements EventSubscriberInterface +{ + private $logger; + public function __construct(LoggerInterface $logger = null) + { + $this->logger = $logger; + } + public function onConsoleError(ConsoleErrorEvent $event) + { + if (null === $this->logger) { + return; + } + $error = $event->getError(); + if (!($inputString = $this->getInputString($event))) { + $this->logger->critical('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]); + return; + } + $this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]); + } + public function onConsoleTerminate(ConsoleTerminateEvent $event) + { + if (null === $this->logger) { + return; + } + $exitCode = $event->getExitCode(); + if (0 === $exitCode) { + return; + } + if (!($inputString = $this->getInputString($event))) { + $this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]); + return; + } + $this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]); + } + public static function getSubscribedEvents() + { + return [ConsoleEvents::ERROR => ['onConsoleError', -128], ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128]]; + } + private static function getInputString(ConsoleEvent $event) + { + $commandName = $event->getCommand() ? $event->getCommand()->getName() : null; + $input = $event->getInput(); + if (\method_exists($input, '__toString')) { + if ($commandName) { + $phabelReturn = \str_replace(["'{$commandName}'", "\"{$commandName}\""], $commandName, (string) $input); + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } + $phabelReturn = (string) $input; + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } + $phabelReturn = $commandName; + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Exception/CommandNotFoundException.php b/vendor-bundle/symfony/console/Exception/CommandNotFoundException.php new file mode 100644 index 000000000..834d70e8a --- /dev/null +++ b/vendor-bundle/symfony/console/Exception/CommandNotFoundException.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Exception; + +/** + * Represents an incorrect command name typed in the console. + * + * @author Jérôme Tamarelle + */ +class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface +{ + private $alternatives; + /** + * @param string $message Exception message to throw + * @param string[] $alternatives List of similar defined names + * @param int $code Exception code + * @param \Throwable|null $previous Previous exception used for the exception chaining + */ + public function __construct($message, array $alternatives = [], $code = 0, \Throwable $previous = null) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_int($code)) { + if (!(\is_bool($code) || \is_numeric($code))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($code) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($code) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $code = (int) $code; + } + } + parent::__construct($message, $code, $previous); + $this->alternatives = $alternatives; + } + /** + * @return string[] A list of similar defined names + */ + public function getAlternatives() + { + return $this->alternatives; + } +} diff --git a/vendor-bundle/symfony/console/Exception/ExceptionInterface.php b/vendor-bundle/symfony/console/Exception/ExceptionInterface.php new file mode 100644 index 000000000..c2e96f54f --- /dev/null +++ b/vendor-bundle/symfony/console/Exception/ExceptionInterface.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Exception; + +/** + * ExceptionInterface. + * + * @author Jérôme Tamarelle + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/vendor-bundle/symfony/console/Exception/InvalidArgumentException.php b/vendor-bundle/symfony/console/Exception/InvalidArgumentException.php new file mode 100644 index 000000000..b2f38b153 --- /dev/null +++ b/vendor-bundle/symfony/console/Exception/InvalidArgumentException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Exception; + +/** + * @author Jérôme Tamarelle + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor-bundle/symfony/console/Exception/InvalidOptionException.php b/vendor-bundle/symfony/console/Exception/InvalidOptionException.php new file mode 100644 index 000000000..ea0fd2097 --- /dev/null +++ b/vendor-bundle/symfony/console/Exception/InvalidOptionException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Exception; + +/** + * Represents an incorrect option name typed in the console. + * + * @author Jérôme Tamarelle + */ +class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor-bundle/symfony/console/Exception/LogicException.php b/vendor-bundle/symfony/console/Exception/LogicException.php new file mode 100644 index 000000000..a89885ad8 --- /dev/null +++ b/vendor-bundle/symfony/console/Exception/LogicException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Exception; + +/** + * @author Jérôme Tamarelle + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/vendor-bundle/symfony/console/Exception/MissingInputException.php b/vendor-bundle/symfony/console/Exception/MissingInputException.php new file mode 100644 index 000000000..37caa54b3 --- /dev/null +++ b/vendor-bundle/symfony/console/Exception/MissingInputException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Exception; + +/** + * Represents failure to read input from stdin. + * + * @author Gabriel Ostrolucký + */ +class MissingInputException extends RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor-bundle/symfony/console/Exception/NamespaceNotFoundException.php b/vendor-bundle/symfony/console/Exception/NamespaceNotFoundException.php new file mode 100644 index 000000000..acd11f57a --- /dev/null +++ b/vendor-bundle/symfony/console/Exception/NamespaceNotFoundException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Exception; + +/** + * Represents an incorrect namespace typed in the console. + * + * @author Pierre du Plessis + */ +class NamespaceNotFoundException extends CommandNotFoundException +{ +} diff --git a/vendor-bundle/symfony/console/Exception/RuntimeException.php b/vendor-bundle/symfony/console/Exception/RuntimeException.php new file mode 100644 index 000000000..aa1f93d74 --- /dev/null +++ b/vendor-bundle/symfony/console/Exception/RuntimeException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Exception; + +/** + * @author Jérôme Tamarelle + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor-bundle/symfony/console/Formatter/NullOutputFormatter.php b/vendor-bundle/symfony/console/Formatter/NullOutputFormatter.php new file mode 100644 index 000000000..40c7a9ad6 --- /dev/null +++ b/vendor-bundle/symfony/console/Formatter/NullOutputFormatter.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Formatter; + +/** + * @author Tien Xuan Vo + */ +final class NullOutputFormatter implements OutputFormatterInterface +{ + private $style; + /** + * {@inheritdoc} + */ + public function format($message) + { + if (!\is_null($message)) { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + } + // do nothing + } + /** + * {@inheritdoc} + */ + public function getStyle($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if ($this->style) { + $phabelReturn = $this->style; + if (!$phabelReturn instanceof OutputFormatterStyleInterface) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type OutputFormatterStyleInterface, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = $this->style = new NullOutputFormatterStyle(); + if (!$phabelReturn instanceof OutputFormatterStyleInterface) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type OutputFormatterStyleInterface, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // to comply with the interface we must return a OutputFormatterStyleInterface + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function hasStyle($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function isDecorated() + { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function setDecorated($decorated) + { + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($decorated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + // do nothing + } + /** + * {@inheritdoc} + */ + public function setStyle($name, OutputFormatterStyleInterface $style) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + // do nothing + } +} diff --git a/vendor-bundle/symfony/console/Formatter/NullOutputFormatterStyle.php b/vendor-bundle/symfony/console/Formatter/NullOutputFormatterStyle.php new file mode 100644 index 000000000..24f2fcb1b --- /dev/null +++ b/vendor-bundle/symfony/console/Formatter/NullOutputFormatterStyle.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Formatter; + +/** + * @author Tien Xuan Vo + */ +final class NullOutputFormatterStyle implements OutputFormatterStyleInterface +{ + /** + * {@inheritdoc} + */ + public function apply($text) + { + if (!\is_string($text)) { + if (!(\is_string($text) || \is_object($text) && \method_exists($text, '__toString') || (\is_bool($text) || \is_numeric($text)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($text) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($text) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $text = (string) $text; + } + } + $phabelReturn = $text; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function setBackground($color = null) + { + if (!\is_null($color)) { + if (!\is_string($color)) { + if (!(\is_string($color) || \is_object($color) && \method_exists($color, '__toString') || (\is_bool($color) || \is_numeric($color)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($color) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($color) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $color = (string) $color; + } + } + } + // do nothing + } + /** + * {@inheritdoc} + */ + public function setForeground($color = null) + { + if (!\is_null($color)) { + if (!\is_string($color)) { + if (!(\is_string($color) || \is_object($color) && \method_exists($color, '__toString') || (\is_bool($color) || \is_numeric($color)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($color) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($color) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $color = (string) $color; + } + } + } + // do nothing + } + /** + * {@inheritdoc} + */ + public function setOption($option) + { + if (!\is_string($option)) { + if (!(\is_string($option) || \is_object($option) && \method_exists($option, '__toString') || (\is_bool($option) || \is_numeric($option)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($option) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($option) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $option = (string) $option; + } + } + // do nothing + } + /** + * {@inheritdoc} + */ + public function setOptions(array $options) + { + // do nothing + } + /** + * {@inheritdoc} + */ + public function unsetOption($option) + { + if (!\is_string($option)) { + if (!(\is_string($option) || \is_object($option) && \method_exists($option, '__toString') || (\is_bool($option) || \is_numeric($option)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($option) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($option) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $option = (string) $option; + } + } + // do nothing + } +} diff --git a/vendor-bundle/symfony/console/Formatter/OutputFormatter.php b/vendor-bundle/symfony/console/Formatter/OutputFormatter.php new file mode 100644 index 000000000..358f3f385 --- /dev/null +++ b/vendor-bundle/symfony/console/Formatter/OutputFormatter.php @@ -0,0 +1,398 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Formatter; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * Formatter class for console output. + * + * @author Konstantin Kudryashov + * @author Roland Franssen + */ +class OutputFormatter implements WrappableOutputFormatterInterface +{ + private $decorated; + private $styles = []; + private $styleStack; + public function __clone() + { + $this->styleStack = clone $this->styleStack; + foreach ($this->styles as $key => $value) { + $this->styles[$key] = clone $value; + } + } + /** + * Escapes "<" special char in given text. + * + * @return string Escaped text + */ + public static function escape($text) + { + if (!\is_string($text)) { + if (!(\is_string($text) || \is_object($text) && \method_exists($text, '__toString') || (\is_bool($text) || \is_numeric($text)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($text) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($text) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $text = (string) $text; + } + } + $text = \preg_replace('/([^\\\\]?) FormatterStyle" instances + */ + public function __construct($decorated = \false, array $styles = []) + { + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($decorated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + $this->decorated = $decorated; + $this->setStyle('error', new OutputFormatterStyle('white', 'red')); + $this->setStyle('info', new OutputFormatterStyle('green')); + $this->setStyle('comment', new OutputFormatterStyle('yellow')); + $this->setStyle('question', new OutputFormatterStyle('black', 'cyan')); + foreach ($styles as $name => $style) { + $this->setStyle($name, $style); + } + $this->styleStack = new OutputFormatterStyleStack(); + } + /** + * {@inheritdoc} + */ + public function setDecorated($decorated) + { + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($decorated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + $this->decorated = $decorated; + } + /** + * {@inheritdoc} + */ + public function isDecorated() + { + return $this->decorated; + } + /** + * {@inheritdoc} + */ + public function setStyle($name, OutputFormatterStyleInterface $style) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $this->styles[\strtolower($name)] = $style; + } + /** + * {@inheritdoc} + */ + public function hasStyle($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + return isset($this->styles[\strtolower($name)]); + } + /** + * {@inheritdoc} + */ + public function getStyle($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!$this->hasStyle($name)) { + throw new InvalidArgumentException(\sprintf('Undefined style: "%s".', $name)); + } + return $this->styles[\strtolower($name)]; + } + /** + * {@inheritdoc} + */ + public function format($message) + { + if (!\is_null($message)) { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + } + return $this->formatAndWrap($message, 0); + } + /** + * {@inheritdoc} + */ + public function formatAndWrap($message, $width) + { + if (!\is_null($message)) { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + } + if (!\is_int($width)) { + if (!(\is_bool($width) || \is_numeric($width))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($width) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($width) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $width = (int) $width; + } + } + $offset = 0; + $output = ''; + $tagRegex = '[a-z][^<>]*+'; + $currentLineLength = 0; + \preg_match_all("#<(({$tagRegex}) | /({$tagRegex})?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE); + foreach ($matches[0] as $i => $match) { + $pos = $match[1]; + $text = $match[0]; + if (0 != $pos && '\\' == $message[$pos - 1]) { + continue; + } + // add the text up to the next tag + $output .= $this->applyCurrentStyle(\substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength); + $offset = $pos + \strlen($text); + // opening tag? + if ($open = '/' != $text[1]) { + $tag = $matches[1][$i][0]; + } else { + $tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : ''; + } + if (!$open && !$tag) { + // + $this->styleStack->pop(); + } elseif (null === ($style = $this->createStyleFromString($tag))) { + $output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength); + } elseif ($open) { + $this->styleStack->push($style); + } else { + $this->styleStack->pop($style); + } + } + $output .= $this->applyCurrentStyle(\substr($message, $offset), $output, $width, $currentLineLength); + if (\str_contains($output, "\x00")) { + return \strtr($output, ["\x00" => '\\', '\\<' => '<']); + } + return \str_replace('\\<', '<', $output); + } + /** + * @return OutputFormatterStyleStack + */ + public function getStyleStack() + { + return $this->styleStack; + } + /** + * Tries to create new style instance from string. + */ + private function createStyleFromString($string) + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + if (isset($this->styles[$string])) { + $phabelReturn = $this->styles[$string]; + if (!($phabelReturn instanceof OutputFormatterStyleInterface || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?OutputFormatterStyleInterface, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if (!\preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, \PREG_SET_ORDER)) { + $phabelReturn = null; + if (!($phabelReturn instanceof OutputFormatterStyleInterface || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?OutputFormatterStyleInterface, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $style = new OutputFormatterStyle(); + foreach ($matches as $match) { + \array_shift($match); + $match[0] = \strtolower($match[0]); + if ('fg' == $match[0]) { + $style->setForeground(\strtolower($match[1])); + } elseif ('bg' == $match[0]) { + $style->setBackground(\strtolower($match[1])); + } elseif ('href' === $match[0]) { + $style->setHref($match[1]); + } elseif ('options' === $match[0]) { + \preg_match_all('([^,;]+)', \strtolower($match[1]), $options); + $options = \array_shift($options); + foreach ($options as $option) { + $style->setOption($option); + } + } else { + $phabelReturn = null; + if (!($phabelReturn instanceof OutputFormatterStyleInterface || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?OutputFormatterStyleInterface, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + } + $phabelReturn = $style; + if (!($phabelReturn instanceof OutputFormatterStyleInterface || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?OutputFormatterStyleInterface, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Applies current style from stack to text, if must be applied. + */ + private function applyCurrentStyle($text, $current, $width, &$currentLineLength) + { + if (!\is_string($text)) { + if (!(\is_string($text) || \is_object($text) && \method_exists($text, '__toString') || (\is_bool($text) || \is_numeric($text)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($text) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($text) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $text = (string) $text; + } + } + if (!\is_string($current)) { + if (!(\is_string($current) || \is_object($current) && \method_exists($current, '__toString') || (\is_bool($current) || \is_numeric($current)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($current) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($current) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $current = (string) $current; + } + } + if (!\is_int($width)) { + if (!(\is_bool($width) || \is_numeric($width))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($width) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($width) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $width = (int) $width; + } + } + if (!\is_int($currentLineLength)) { + if (!(\is_bool($currentLineLength) || \is_numeric($currentLineLength))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($currentLineLength) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($currentLineLength) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $currentLineLength = (int) $currentLineLength; + } + } + if ('' === $text) { + $phabelReturn = ''; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (!$width) { + $phabelReturn = $this->isDecorated() ? $this->styleStack->getCurrent()->apply($text) : $text; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (!$currentLineLength && '' !== $current) { + $text = \ltrim($text); + } + if ($currentLineLength) { + $prefix = \substr($text, 0, $i = $width - $currentLineLength) . "\n"; + $text = \substr($text, $i); + } else { + $prefix = ''; + } + \preg_match('~(\\n)$~', $text, $matches); + $text = $prefix . \preg_replace('~([^\\n]{' . $width . '})\\ *~', "\$1\n", $text); + $text = \rtrim($text, "\n") . (isset($matches[1]) ? $matches[1] : ''); + if (!$currentLineLength && '' !== $current && "\n" !== \substr($current, -1)) { + $text = "\n" . $text; + } + $lines = \explode("\n", $text); + foreach ($lines as $line) { + $currentLineLength += \strlen($line); + if ($width <= $currentLineLength) { + $currentLineLength = 0; + } + } + if ($this->isDecorated()) { + foreach ($lines as $i => $line) { + $lines[$i] = $this->styleStack->getCurrent()->apply($line); + } + } + $phabelReturn = \implode("\n", $lines); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Formatter/OutputFormatterInterface.php b/vendor-bundle/symfony/console/Formatter/OutputFormatterInterface.php new file mode 100644 index 000000000..da701f972 --- /dev/null +++ b/vendor-bundle/symfony/console/Formatter/OutputFormatterInterface.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Formatter; + +/** + * Formatter interface for console output. + * + * @author Konstantin Kudryashov + */ +interface OutputFormatterInterface +{ + /** + * Sets the decorated flag. + */ + public function setDecorated($decorated); + /** + * Gets the decorated flag. + * + * @return bool true if the output will decorate messages, false otherwise + */ + public function isDecorated(); + /** + * Sets a new style. + */ + public function setStyle($name, OutputFormatterStyleInterface $style); + /** + * Checks if output formatter has style with specified name. + * + * @return bool + */ + public function hasStyle($name); + /** + * Gets style options from style with specified name. + * + * @return OutputFormatterStyleInterface + * + * @throws \InvalidArgumentException When style isn't defined + */ + public function getStyle($name); + /** + * Formats a message according to the given styles. + */ + public function format($message); +} diff --git a/vendor-bundle/symfony/console/Formatter/OutputFormatterStyle.php b/vendor-bundle/symfony/console/Formatter/OutputFormatterStyle.php new file mode 100644 index 000000000..5a537f859 --- /dev/null +++ b/vendor-bundle/symfony/console/Formatter/OutputFormatterStyle.php @@ -0,0 +1,158 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Formatter; + +use Phabel\Symfony\Component\Console\Color; +/** + * Formatter style class for defining styles. + * + * @author Konstantin Kudryashov + */ +class OutputFormatterStyle implements OutputFormatterStyleInterface +{ + private $color; + private $foreground; + private $background; + private $options; + private $href; + private $handlesHrefGracefully; + /** + * Initializes output formatter style. + * + * @param string|null $foreground The style foreground color name + * @param string|null $background The style background color name + */ + public function __construct($foreground = null, $background = null, array $options = []) + { + if (!\is_null($foreground)) { + if (!\is_string($foreground)) { + if (!(\is_string($foreground) || \is_object($foreground) && \method_exists($foreground, '__toString') || (\is_bool($foreground) || \is_numeric($foreground)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($foreground) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($foreground) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $foreground = (string) $foreground; + } + } + } + if (!\is_null($background)) { + if (!\is_string($background)) { + if (!(\is_string($background) || \is_object($background) && \method_exists($background, '__toString') || (\is_bool($background) || \is_numeric($background)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($background) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($background) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $background = (string) $background; + } + } + } + $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options); + } + /** + * {@inheritdoc} + */ + public function setForeground($color = null) + { + if (!\is_null($color)) { + if (!\is_string($color)) { + if (!(\is_string($color) || \is_object($color) && \method_exists($color, '__toString') || (\is_bool($color) || \is_numeric($color)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($color) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($color) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $color = (string) $color; + } + } + } + $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options); + } + /** + * {@inheritdoc} + */ + public function setBackground($color = null) + { + if (!\is_null($color)) { + if (!\is_string($color)) { + if (!(\is_string($color) || \is_object($color) && \method_exists($color, '__toString') || (\is_bool($color) || \is_numeric($color)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($color) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($color) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $color = (string) $color; + } + } + } + $this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options); + } + public function setHref($url) + { + if (!\is_string($url)) { + if (!(\is_string($url) || \is_object($url) && \method_exists($url, '__toString') || (\is_bool($url) || \is_numeric($url)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($url) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($url) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $url = (string) $url; + } + } + $this->href = $url; + } + /** + * {@inheritdoc} + */ + public function setOption($option) + { + if (!\is_string($option)) { + if (!(\is_string($option) || \is_object($option) && \method_exists($option, '__toString') || (\is_bool($option) || \is_numeric($option)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($option) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($option) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $option = (string) $option; + } + } + $this->options[] = $option; + $this->color = new Color($this->foreground, $this->background, $this->options); + } + /** + * {@inheritdoc} + */ + public function unsetOption($option) + { + if (!\is_string($option)) { + if (!(\is_string($option) || \is_object($option) && \method_exists($option, '__toString') || (\is_bool($option) || \is_numeric($option)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($option) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($option) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $option = (string) $option; + } + } + $pos = \array_search($option, $this->options); + if (\false !== $pos) { + unset($this->options[$pos]); + } + $this->color = new Color($this->foreground, $this->background, $this->options); + } + /** + * {@inheritdoc} + */ + public function setOptions(array $options) + { + $this->color = new Color($this->foreground, $this->background, $this->options = $options); + } + /** + * {@inheritdoc} + */ + public function apply($text) + { + if (!\is_string($text)) { + if (!(\is_string($text) || \is_object($text) && \method_exists($text, '__toString') || (\is_bool($text) || \is_numeric($text)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($text) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($text) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $text = (string) $text; + } + } + if (null === $this->handlesHrefGracefully) { + $this->handlesHrefGracefully = 'JetBrains-JediTerm' !== \getenv('TERMINAL_EMULATOR') && (!\getenv('KONSOLE_VERSION') || (int) \getenv('KONSOLE_VERSION') > 201100); + } + if (null !== $this->href && $this->handlesHrefGracefully) { + $text = "\x1b]8;;{$this->href}\x1b\\{$text}\x1b]8;;\x1b\\"; + } + return $this->color->apply($text); + } +} diff --git a/vendor-bundle/symfony/console/Formatter/OutputFormatterStyleInterface.php b/vendor-bundle/symfony/console/Formatter/OutputFormatterStyleInterface.php new file mode 100644 index 000000000..ff8efb583 --- /dev/null +++ b/vendor-bundle/symfony/console/Formatter/OutputFormatterStyleInterface.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Formatter; + +/** + * Formatter style interface for defining styles. + * + * @author Konstantin Kudryashov + */ +interface OutputFormatterStyleInterface +{ + /** + * Sets style foreground color. + */ + public function setForeground($color = null); + /** + * Sets style background color. + */ + public function setBackground($color = null); + /** + * Sets some specific style option. + */ + public function setOption($option); + /** + * Unsets some specific style option. + */ + public function unsetOption($option); + /** + * Sets multiple style options at once. + */ + public function setOptions(array $options); + /** + * Applies the style to a given text. + * + * @return string + */ + public function apply($text); +} diff --git a/vendor-bundle/symfony/console/Formatter/OutputFormatterStyleStack.php b/vendor-bundle/symfony/console/Formatter/OutputFormatterStyleStack.php new file mode 100644 index 000000000..470f67759 --- /dev/null +++ b/vendor-bundle/symfony/console/Formatter/OutputFormatterStyleStack.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Formatter; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Contracts\Service\ResetInterface; +/** + * @author Jean-François Simon + */ +class OutputFormatterStyleStack implements ResetInterface +{ + /** + * @var OutputFormatterStyleInterface[] + */ + private $styles; + private $emptyStyle; + public function __construct(OutputFormatterStyleInterface $emptyStyle = null) + { + $this->emptyStyle = isset($emptyStyle) ? $emptyStyle : new OutputFormatterStyle(); + $this->reset(); + } + /** + * Resets stack (ie. empty internal arrays). + */ + public function reset() + { + $this->styles = []; + } + /** + * Pushes a style in the stack. + */ + public function push(OutputFormatterStyleInterface $style) + { + $this->styles[] = $style; + } + /** + * Pops a style from the stack. + * + * @return OutputFormatterStyleInterface + * + * @throws InvalidArgumentException When style tags incorrectly nested + */ + public function pop(OutputFormatterStyleInterface $style = null) + { + if (empty($this->styles)) { + return $this->emptyStyle; + } + if (null === $style) { + return \array_pop($this->styles); + } + foreach (\array_reverse($this->styles, \true) as $index => $stackedStyle) { + if ($style->apply('') === $stackedStyle->apply('')) { + $this->styles = \array_slice($this->styles, 0, $index); + return $stackedStyle; + } + } + throw new InvalidArgumentException('Incorrectly nested style tag found.'); + } + /** + * Computes current style with stacks top codes. + * + * @return OutputFormatterStyle + */ + public function getCurrent() + { + if (empty($this->styles)) { + return $this->emptyStyle; + } + return $this->styles[\count($this->styles) - 1]; + } + /** + * @return $this + */ + public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle) + { + $this->emptyStyle = $emptyStyle; + return $this; + } + /** + * @return OutputFormatterStyleInterface + */ + public function getEmptyStyle() + { + return $this->emptyStyle; + } +} diff --git a/vendor-bundle/symfony/console/Formatter/WrappableOutputFormatterInterface.php b/vendor-bundle/symfony/console/Formatter/WrappableOutputFormatterInterface.php new file mode 100644 index 000000000..2643728af --- /dev/null +++ b/vendor-bundle/symfony/console/Formatter/WrappableOutputFormatterInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Formatter; + +/** + * Formatter interface for console output that supports word wrapping. + * + * @author Roland Franssen + */ +interface WrappableOutputFormatterInterface extends OutputFormatterInterface +{ + /** + * Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping). + */ + public function formatAndWrap($message, $width); +} diff --git a/vendor-bundle/symfony/console/Helper/DebugFormatterHelper.php b/vendor-bundle/symfony/console/Helper/DebugFormatterHelper.php new file mode 100644 index 000000000..8741092cc --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/DebugFormatterHelper.php @@ -0,0 +1,191 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +/** + * Helps outputting debug information when running an external program from a command. + * + * An external program can be a Process, an HTTP request, or anything else. + * + * @author Fabien Potencier + */ +class DebugFormatterHelper extends Helper +{ + private $colors = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default']; + private $started = []; + private $count = -1; + /** + * Starts a debug formatting session. + * + * @return string + */ + public function start($id, $message, $prefix = 'RUN') + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_string($prefix)) { + if (!(\is_string($prefix) || \is_object($prefix) && \method_exists($prefix, '__toString') || (\is_bool($prefix) || \is_numeric($prefix)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($prefix) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($prefix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $prefix = (string) $prefix; + } + } + $this->started[$id] = ['border' => ++$this->count % \count($this->colors)]; + return \sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); + } + /** + * Adds progress to a formatting session. + * + * @return string + */ + public function progress($id, $buffer, $error = \false, $prefix = 'OUT', $errorPrefix = 'ERR') + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + if (!\is_string($buffer)) { + if (!(\is_string($buffer) || \is_object($buffer) && \method_exists($buffer, '__toString') || (\is_bool($buffer) || \is_numeric($buffer)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($buffer) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($buffer) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $buffer = (string) $buffer; + } + } + if (!\is_bool($error)) { + if (!(\is_bool($error) || \is_numeric($error) || \is_string($error))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($error) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($error) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $error = (bool) $error; + } + } + if (!\is_string($prefix)) { + if (!(\is_string($prefix) || \is_object($prefix) && \method_exists($prefix, '__toString') || (\is_bool($prefix) || \is_numeric($prefix)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($prefix) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($prefix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $prefix = (string) $prefix; + } + } + if (!\is_string($errorPrefix)) { + if (!(\is_string($errorPrefix) || \is_object($errorPrefix) && \method_exists($errorPrefix, '__toString') || (\is_bool($errorPrefix) || \is_numeric($errorPrefix)))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($errorPrefix) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($errorPrefix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $errorPrefix = (string) $errorPrefix; + } + } + $message = ''; + if ($error) { + if (isset($this->started[$id]['out'])) { + $message .= "\n"; + unset($this->started[$id]['out']); + } + if (!isset($this->started[$id]['err'])) { + $message .= \sprintf('%s %s ', $this->getBorder($id), $errorPrefix); + $this->started[$id]['err'] = \true; + } + $message .= \str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); + } else { + if (isset($this->started[$id]['err'])) { + $message .= "\n"; + unset($this->started[$id]['err']); + } + if (!isset($this->started[$id]['out'])) { + $message .= \sprintf('%s %s ', $this->getBorder($id), $prefix); + $this->started[$id]['out'] = \true; + } + $message .= \str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); + } + return $message; + } + /** + * Stops a formatting session. + * + * @return string + */ + public function stop($id, $message, $successful, $prefix = 'RES') + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_bool($successful)) { + if (!(\is_bool($successful) || \is_numeric($successful) || \is_string($successful))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($successful) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($successful) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $successful = (bool) $successful; + } + } + if (!\is_string($prefix)) { + if (!(\is_string($prefix) || \is_object($prefix) && \method_exists($prefix, '__toString') || (\is_bool($prefix) || \is_numeric($prefix)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($prefix) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($prefix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $prefix = (string) $prefix; + } + } + $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : ''; + if ($successful) { + return \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + } + $message = \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + unset($this->started[$id]['out'], $this->started[$id]['err']); + return $message; + } + private function getBorder($id) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + $phabelReturn = \sprintf(' ', $this->colors[$this->started[$id]['border']]); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function getName() + { + return 'debug_formatter'; + } +} diff --git a/vendor-bundle/symfony/console/Helper/DescriptorHelper.php b/vendor-bundle/symfony/console/Helper/DescriptorHelper.php new file mode 100644 index 000000000..706c08384 --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/DescriptorHelper.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Descriptor\DescriptorInterface; +use Phabel\Symfony\Component\Console\Descriptor\JsonDescriptor; +use Phabel\Symfony\Component\Console\Descriptor\MarkdownDescriptor; +use Phabel\Symfony\Component\Console\Descriptor\TextDescriptor; +use Phabel\Symfony\Component\Console\Descriptor\XmlDescriptor; +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * This class adds helper method to describe objects in various formats. + * + * @author Jean-François Simon + */ +class DescriptorHelper extends Helper +{ + /** + * @var DescriptorInterface[] + */ + private $descriptors = []; + public function __construct() + { + $this->register('txt', new TextDescriptor())->register('xml', new XmlDescriptor())->register('json', new JsonDescriptor())->register('md', new MarkdownDescriptor()); + } + /** + * Describes an object if supported. + * + * Available options are: + * * format: string, the output format name + * * raw_text: boolean, sets output type as raw + * + * @throws InvalidArgumentException when the given format is not supported + */ + public function describe(OutputInterface $output, $object, array $options = []) + { + if (!(\is_object($object) || \is_null($object))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($object) must be of type ?object, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($object) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $options = \array_merge(['raw_text' => \false, 'format' => 'txt'], $options); + if (!isset($this->descriptors[$options['format']])) { + throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $options['format'])); + } + $descriptor = $this->descriptors[$options['format']]; + $descriptor->describe($output, $object, $options); + } + /** + * Registers a descriptor. + * + * @return $this + */ + public function register($format, DescriptorInterface $descriptor) + { + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $format = (string) $format; + } + } + $this->descriptors[$format] = $descriptor; + return $this; + } + /** + * {@inheritdoc} + */ + public function getName() + { + return 'descriptor'; + } +} diff --git a/vendor-bundle/symfony/console/Helper/Dumper.php b/vendor-bundle/symfony/console/Helper/Dumper.php new file mode 100644 index 000000000..61351b34e --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/Dumper.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Output\OutputInterface; +use Phabel\Symfony\Component\VarDumper\Cloner\ClonerInterface; +use Phabel\Symfony\Component\VarDumper\Cloner\VarCloner; +use Phabel\Symfony\Component\VarDumper\Dumper\CliDumper; +/** + * @author Roland Franssen + */ +final class Dumper +{ + private $output; + private $dumper; + private $cloner; + private $handler; + public function __construct(OutputInterface $output, CliDumper $dumper = null, ClonerInterface $cloner = null) + { + $this->output = $output; + $this->dumper = $dumper; + $this->cloner = $cloner; + if (\class_exists(CliDumper::class)) { + $this->handler = function ($var) { + $dumper = isset($this->dumper) ? $this->dumper : ($this->dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR)); + $dumper->setColors($this->output->isDecorated()); + $phabelReturn = \rtrim($dumper->dump(\Phabel\Plugin\NestedExpressionFixer::returnMe(isset($this->cloner) ? $this->cloner : ($this->cloner = new VarCloner()))->cloneVar($var)->withRefHandles(\false), \true)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + }; + } else { + $this->handler = function ($var) { + switch (\true) { + case null === $var: + $phabelReturn = 'null'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \true === $var: + $phabelReturn = 'true'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \false === $var: + $phabelReturn = 'false'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \is_string($var): + $phabelReturn = '"' . $var . '"'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + default: + $phabelReturn = \rtrim(\print_r($var, \true)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + }; + } + } + public function __invoke($var) + { + $phabel_14a91fe07c519d84 = $this->handler; + $phabelReturn = $phabel_14a91fe07c519d84($var); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Helper/FormatterHelper.php b/vendor-bundle/symfony/console/Helper/FormatterHelper.php new file mode 100644 index 000000000..5ee4b1833 --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/FormatterHelper.php @@ -0,0 +1,137 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Formatter\OutputFormatter; +/** + * The Formatter class provides helpers to format messages. + * + * @author Fabien Potencier + */ +class FormatterHelper extends Helper +{ + /** + * Formats a message within a section. + * + * @return string The format section + */ + public function formatSection($section, $message, $style = 'info') + { + if (!\is_string($section)) { + if (!(\is_string($section) || \is_object($section) && \method_exists($section, '__toString') || (\is_bool($section) || \is_numeric($section)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($section) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($section) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $section = (string) $section; + } + } + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_string($style)) { + if (!(\is_string($style) || \is_object($style) && \method_exists($style, '__toString') || (\is_bool($style) || \is_numeric($style)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($style) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($style) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $style = (string) $style; + } + } + return \sprintf('<%s>[%s] %s', $style, $section, $style, $message); + } + /** + * Formats a message as a block of text. + * + * @param string|array $messages The message to write in the block + * + * @return string The formatter message + */ + public function formatBlock($messages, $style, $large = \false) + { + if (!\is_string($style)) { + if (!(\is_string($style) || \is_object($style) && \method_exists($style, '__toString') || (\is_bool($style) || \is_numeric($style)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($style) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($style) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $style = (string) $style; + } + } + if (!\is_bool($large)) { + if (!(\is_bool($large) || \is_numeric($large) || \is_string($large))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($large) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($large) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $large = (bool) $large; + } + } + if (!\is_array($messages)) { + $messages = [$messages]; + } + $len = 0; + $lines = []; + foreach ($messages as $message) { + $message = OutputFormatter::escape($message); + $lines[] = \sprintf($large ? ' %s ' : ' %s ', $message); + $len = \max(self::width($message) + ($large ? 4 : 2), $len); + } + $messages = $large ? [\str_repeat(' ', $len)] : []; + for ($i = 0; isset($lines[$i]); ++$i) { + $messages[] = $lines[$i] . \str_repeat(' ', $len - self::width($lines[$i])); + } + if ($large) { + $messages[] = \str_repeat(' ', $len); + } + for ($i = 0; isset($messages[$i]); ++$i) { + $messages[$i] = \sprintf('<%s>%s', $style, $messages[$i], $style); + } + return \implode("\n", $messages); + } + /** + * Truncates a message to the given length. + * + * @return string + */ + public function truncate($message, $length, $suffix = '...') + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + if (!\is_string($suffix)) { + if (!(\is_string($suffix) || \is_object($suffix) && \method_exists($suffix, '__toString') || (\is_bool($suffix) || \is_numeric($suffix)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($suffix) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($suffix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $suffix = (string) $suffix; + } + } + $computedLength = $length - self::width($suffix); + if ($computedLength > self::width($message)) { + return $message; + } + return self::substr($message, 0, $length) . $suffix; + } + /** + * {@inheritdoc} + */ + public function getName() + { + return 'formatter'; + } +} diff --git a/vendor-bundle/symfony/console/Helper/Helper.php b/vendor-bundle/symfony/console/Helper/Helper.php new file mode 100644 index 000000000..0248ff622 --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/Helper.php @@ -0,0 +1,263 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Phabel\Symfony\Component\String\UnicodeString; +/** + * Helper is the base class for all helper classes. + * + * @author Fabien Potencier + */ +abstract class Helper implements HelperInterface +{ + protected $helperSet = null; + /** + * {@inheritdoc} + */ + public function setHelperSet(HelperSet $helperSet = null) + { + $this->helperSet = $helperSet; + } + /** + * {@inheritdoc} + */ + public function getHelperSet() + { + return $this->helperSet; + } + /** + * Returns the length of a string, using mb_strwidth if it is available. + * + * @deprecated since 5.3 + * + * @return int The length of the string + */ + public static function strlen($string) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + trigger_deprecation('symfony/console', '5.3', 'Method "%s()" is deprecated and will be removed in Symfony 6.0. Use Helper::width() or Helper::length() instead.', __METHOD__); + return self::width($string); + } + /** + * Returns the width of a string, using mb_strwidth if it is available. + * The width is how many characters positions the string will use. + */ + public static function width($string) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + isset($string) ? $string : ($string = ''); + if (\preg_match('//u', $string)) { + $phabelReturn = (new UnicodeString($string))->width(\false); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) { + $phabelReturn = \strlen($string); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \mb_strwidth($string, $encoding); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Returns the length of a string, using mb_strlen if it is available. + * The length is related to how many bytes the string will use. + */ + public static function length($string) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + isset($string) ? $string : ($string = ''); + if (\preg_match('//u', $string)) { + $phabelReturn = (new UnicodeString($string))->length(); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) { + $phabelReturn = \strlen($string); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \mb_strlen($string, $encoding); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Returns the subset of a string, using mb_substr if it is available. + * + * @return string The string subset + */ + public static function substr($string, $from, $length = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_int($from)) { + if (!(\is_bool($from) || \is_numeric($from))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($from) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($from) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $from = (int) $from; + } + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + } + isset($string) ? $string : ($string = ''); + if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) { + return \substr($string, $from, $length); + } + return \mb_substr($string, $from, $length, $encoding); + } + public static function formatTime($secs) + { + static $timeFormats = [[0, '< 1 sec'], [1, '1 sec'], [2, 'secs', 1], [60, '1 min'], [120, 'mins', 60], [3600, '1 hr'], [7200, 'hrs', 3600], [86400, '1 day'], [172800, 'days', 86400]]; + foreach ($timeFormats as $index => $format) { + if ($secs >= $format[0]) { + if (isset($timeFormats[$index + 1]) && $secs < $timeFormats[$index + 1][0] || $index == \count($timeFormats) - 1) { + if (2 == \count($format)) { + return $format[1]; + } + return \floor($secs / $format[2]) . ' ' . $format[1]; + } + } + } + } + public static function formatMemory($memory) + { + if (!\is_int($memory)) { + if (!(\is_bool($memory) || \is_numeric($memory))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($memory) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($memory) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $memory = (int) $memory; + } + } + if ($memory >= 1024 * 1024 * 1024) { + return \sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); + } + if ($memory >= 1024 * 1024) { + return \sprintf('%.1f MiB', $memory / 1024 / 1024); + } + if ($memory >= 1024) { + return \sprintf('%d KiB', $memory / 1024); + } + return \sprintf('%d B', $memory); + } + /** + * @deprecated since 5.3 + */ + public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + trigger_deprecation('symfony/console', '5.3', 'Method "%s()" is deprecated and will be removed in Symfony 6.0. Use Helper::removeDecoration() instead.', __METHOD__); + return self::width(self::removeDecoration($formatter, $string)); + } + public static function removeDecoration(OutputFormatterInterface $formatter, $string) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + $isDecorated = $formatter->isDecorated(); + $formatter->setDecorated(\false); + // remove <...> formatting + $string = $formatter->format(isset($string) ? $string : ''); + // remove already formatted characters + $string = \preg_replace("/\x1b\\[[^m]*m/", '', $string); + $formatter->setDecorated($isDecorated); + return $string; + } +} diff --git a/vendor-bundle/symfony/console/Helper/HelperInterface.php b/vendor-bundle/symfony/console/Helper/HelperInterface.php new file mode 100644 index 000000000..d52dee5a9 --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/HelperInterface.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +/** + * HelperInterface is the interface all helpers must implement. + * + * @author Fabien Potencier + */ +interface HelperInterface +{ + /** + * Sets the helper set associated with this helper. + */ + public function setHelperSet(HelperSet $helperSet = null); + /** + * Gets the helper set associated with this helper. + * + * @return HelperSet A HelperSet instance + */ + public function getHelperSet(); + /** + * Returns the canonical name of this helper. + * + * @return string The canonical name + */ + public function getName(); +} diff --git a/vendor-bundle/symfony/console/Helper/HelperSet.php b/vendor-bundle/symfony/console/Helper/HelperSet.php new file mode 100644 index 000000000..ae0e0f91f --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/HelperSet.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * HelperSet represents a set of helpers to be used with a command. + * + * @author Fabien Potencier + */ +class HelperSet implements \IteratorAggregate +{ + /** + * @var Helper[] + */ + private $helpers = []; + private $command; + /** + * @param Helper[] $helpers An array of helper + */ + public function __construct(array $helpers = []) + { + foreach ($helpers as $alias => $helper) { + $this->set($helper, \is_int($alias) ? null : $alias); + } + } + public function set(HelperInterface $helper, $alias = null) + { + if (!\is_null($alias)) { + if (!\is_string($alias)) { + if (!(\is_string($alias) || \is_object($alias) && \method_exists($alias, '__toString') || (\is_bool($alias) || \is_numeric($alias)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($alias) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($alias) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $alias = (string) $alias; + } + } + } + $this->helpers[$helper->getName()] = $helper; + if (null !== $alias) { + $this->helpers[$alias] = $helper; + } + $helper->setHelperSet($this); + } + /** + * Returns true if the helper if defined. + * + * @return bool true if the helper is defined, false otherwise + */ + public function has($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + return isset($this->helpers[$name]); + } + /** + * Gets a helper value. + * + * @return HelperInterface The helper instance + * + * @throws InvalidArgumentException if the helper is not defined + */ + public function get($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!$this->has($name)) { + throw new InvalidArgumentException(\sprintf('The helper "%s" is not defined.', $name)); + } + return $this->helpers[$name]; + } + public function setCommand(Command $command = null) + { + $this->command = $command; + } + /** + * Gets the command associated with this helper set. + * + * @return Command A Command instance + */ + public function getCommand() + { + return $this->command; + } + /** + * @return Helper[] + */ + public function getIterator() + { + return new \ArrayIterator($this->helpers); + } +} diff --git a/vendor-bundle/symfony/console/Helper/InputAwareHelper.php b/vendor-bundle/symfony/console/Helper/InputAwareHelper.php new file mode 100644 index 000000000..ca6b788cc --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/InputAwareHelper.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Input\InputAwareInterface; +use Phabel\Symfony\Component\Console\Input\InputInterface; +/** + * An implementation of InputAwareInterface for Helpers. + * + * @author Wouter J + */ +abstract class InputAwareHelper extends Helper implements InputAwareInterface +{ + protected $input; + /** + * {@inheritdoc} + */ + public function setInput(InputInterface $input) + { + $this->input = $input; + } +} diff --git a/vendor-bundle/symfony/console/Helper/ProcessHelper.php b/vendor-bundle/symfony/console/Helper/ProcessHelper.php new file mode 100644 index 000000000..f78dd2357 --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/ProcessHelper.php @@ -0,0 +1,186 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Output\ConsoleOutputInterface; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +use Phabel\Symfony\Component\Process\Exception\ProcessFailedException; +use Phabel\Symfony\Component\Process\Process; +/** + * The ProcessHelper class provides helpers to run external processes. + * + * @author Fabien Potencier + * + * @final + */ +class ProcessHelper extends Helper +{ + /** + * Runs an external process. + * + * @param array|Process $cmd An instance of Process or an array of the command and arguments + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @return Process The process that ran + */ + public function run(OutputInterface $output, $cmd, $error = null, callable $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE) + { + if (!\is_null($error)) { + if (!\is_string($error)) { + if (!(\is_string($error) || \is_object($error) && \method_exists($error, '__toString') || (\is_bool($error) || \is_numeric($error)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($error) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($error) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $error = (string) $error; + } + } + } + if (!\is_int($verbosity)) { + if (!(\is_bool($verbosity) || \is_numeric($verbosity))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($verbosity) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($verbosity) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $verbosity = (int) $verbosity; + } + } + if (!\class_exists(Process::class)) { + throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".'); + } + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + $formatter = $this->getHelperSet()->get('debug_formatter'); + if ($cmd instanceof Process) { + $cmd = [$cmd]; + } + if (!\is_array($cmd)) { + throw new \TypeError(\sprintf('The "command" argument of "%s()" must be an array or a "%s" instance, "%s" given.', __METHOD__, Process::class, \get_debug_type($cmd))); + } + if (\is_string(isset($cmd[0]) ? $cmd[0] : null)) { + $process = new Process($cmd); + $cmd = []; + } elseif ((isset($cmd[0]) ? $cmd[0] : null) instanceof Process) { + $process = $cmd[0]; + unset($cmd[0]); + } else { + throw new \InvalidArgumentException(\sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); + } + if ($verbosity <= $output->getVerbosity()) { + $output->write($formatter->start(\spl_object_hash($process), $this->escapeString($process->getCommandLine()))); + } + if ($output->isDebug()) { + $callback = $this->wrapCallback($output, $process, $callback); + } + $process->run($callback, $cmd); + if ($verbosity <= $output->getVerbosity()) { + $message = $process->isSuccessful() ? 'Command ran successfully' : \sprintf('%s Command did not run successfully', $process->getExitCode()); + $output->write($formatter->stop(\spl_object_hash($process), $message, $process->isSuccessful())); + } + if (!$process->isSuccessful() && null !== $error) { + $output->writeln(\sprintf('%s', $this->escapeString($error))); + } + $phabelReturn = $process; + if (!$phabelReturn instanceof Process) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Process, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Runs the process. + * + * This is identical to run() except that an exception is thrown if the process + * exits with a non-zero exit code. + * + * @param string|Process $cmd An instance of Process or a command to run + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @return Process The process that ran + * + * @throws ProcessFailedException + * + * @see run() + */ + public function mustRun(OutputInterface $output, $cmd, $error = null, callable $callback = null) + { + if (!\is_null($error)) { + if (!\is_string($error)) { + if (!(\is_string($error) || \is_object($error) && \method_exists($error, '__toString') || (\is_bool($error) || \is_numeric($error)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($error) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($error) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $error = (string) $error; + } + } + } + $process = $this->run($output, $cmd, $error, $callback); + if (!$process->isSuccessful()) { + throw new ProcessFailedException($process); + } + $phabelReturn = $process; + if (!$phabelReturn instanceof Process) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Process, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Wraps a Process callback to add debugging output. + */ + public function wrapCallback(OutputInterface $output, Process $process, callable $callback = null) + { + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + $formatter = $this->getHelperSet()->get('debug_formatter'); + $phabelReturn = function ($type, $buffer) use($output, $process, $callback, $formatter) { + $output->write($formatter->progress(\spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type)); + if (null !== $callback) { + $callback($type, $buffer); + } + }; + if (!\is_callable($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function escapeString($str) + { + if (!\is_string($str)) { + if (!(\is_string($str) || \is_object($str) && \method_exists($str, '__toString') || (\is_bool($str) || \is_numeric($str)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($str) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($str) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $str = (string) $str; + } + } + $phabelReturn = \str_replace('<', '\\<', $str); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function getName() + { + $phabelReturn = 'process'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Helper/ProgressBar.php b/vendor-bundle/symfony/console/Helper/ProgressBar.php new file mode 100644 index 000000000..603e34e95 --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/ProgressBar.php @@ -0,0 +1,887 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Cursor; +use Phabel\Symfony\Component\Console\Exception\LogicException; +use Phabel\Symfony\Component\Console\Output\ConsoleOutputInterface; +use Phabel\Symfony\Component\Console\Output\ConsoleSectionOutput; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +use Phabel\Symfony\Component\Console\Terminal; +/** + * The ProgressBar provides helpers to display progress output. + * + * @author Fabien Potencier + * @author Chris Jones + */ +final class ProgressBar +{ + const FORMAT_VERBOSE = 'verbose'; + const FORMAT_VERY_VERBOSE = 'very_verbose'; + const FORMAT_DEBUG = 'debug'; + const FORMAT_NORMAL = 'normal'; + const FORMAT_VERBOSE_NOMAX = 'verbose_nomax'; + const FORMAT_VERY_VERBOSE_NOMAX = 'very_verbose_nomax'; + const FORMAT_DEBUG_NOMAX = 'debug_nomax'; + const FORMAT_NORMAL_NOMAX = 'normal_nomax'; + private $barWidth = 28; + private $barChar; + private $emptyBarChar = '-'; + private $progressChar = '>'; + private $format; + private $internalFormat; + private $redrawFreq = 1; + private $writeCount; + private $lastWriteTime; + private $minSecondsBetweenRedraws = 0; + private $maxSecondsBetweenRedraws = 1; + private $output; + private $step = 0; + private $max; + private $startTime; + private $stepWidth; + private $percent = 0.0; + private $formatLineCount; + private $messages = []; + private $overwrite = \true; + private $terminal; + private $previousMessage; + private $cursor; + private static $formatters; + private static $formats; + /** + * @param int $max Maximum steps (0 if unknown) + */ + public function __construct(OutputInterface $output, $max = 0, $minSecondsBetweenRedraws = 1 / 25) + { + if (!\is_int($max)) { + if (!(\is_bool($max) || \is_numeric($max))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($max) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($max) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $max = (int) $max; + } + } + if (!\is_float($minSecondsBetweenRedraws)) { + if (!(\is_bool($minSecondsBetweenRedraws) || \is_numeric($minSecondsBetweenRedraws))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($minSecondsBetweenRedraws) must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($minSecondsBetweenRedraws) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $minSecondsBetweenRedraws = (double) $minSecondsBetweenRedraws; + } + } + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + $this->output = $output; + $this->setMaxSteps($max); + $this->terminal = new Terminal(); + if (0 < $minSecondsBetweenRedraws) { + $this->redrawFreq = null; + $this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws; + } + if (!$this->output->isDecorated()) { + // disable overwrite when output does not support ANSI codes. + $this->overwrite = \false; + // set a reasonable redraw frequency so output isn't flooded + $this->redrawFreq = null; + } + $this->startTime = \time(); + $this->cursor = new Cursor($output); + } + /** + * Sets a placeholder formatter for a given name. + * + * This method also allow you to override an existing placeholder. + * + * @param string $name The placeholder name (including the delimiter char like %) + * @param callable $callable A PHP callable + */ + public static function setPlaceholderFormatterDefinition($name, callable $callable) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!self::$formatters) { + self::$formatters = self::initPlaceholderFormatters(); + } + self::$formatters[$name] = $callable; + } + /** + * Gets the placeholder formatter for a given name. + * + * @param string $name The placeholder name (including the delimiter char like %) + * + * @return callable|null A PHP callable + */ + public static function getPlaceholderFormatterDefinition($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!self::$formatters) { + self::$formatters = self::initPlaceholderFormatters(); + } + $phabelReturn = isset(self::$formatters[$name]) ? self::$formatters[$name] : null; + if (!(\is_callable($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Sets a format for a given name. + * + * This method also allow you to override an existing format. + * + * @param string $name The format name + * @param string $format A format string + */ + public static function setFormatDefinition($name, $format) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $format = (string) $format; + } + } + if (!self::$formats) { + self::$formats = self::initFormats(); + } + self::$formats[$name] = $format; + } + /** + * Gets the format for a given name. + * + * @param string $name The format name + * + * @return string|null A format string + */ + public static function getFormatDefinition($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!self::$formats) { + self::$formats = self::initFormats(); + } + $phabelReturn = isset(self::$formats[$name]) ? self::$formats[$name] : null; + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } + /** + * Associates a text with a named placeholder. + * + * The text is displayed when the progress bar is rendered but only + * when the corresponding placeholder is part of the custom format line + * (by wrapping the name with %). + * + * @param string $message The text to associate with the placeholder + * @param string $name The name of the placeholder + */ + public function setMessage($message, $name = 'message') + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $this->messages[$name] = $message; + } + public function getMessage($name = 'message') + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + return $this->messages[$name]; + } + public function getStartTime() + { + $phabelReturn = $this->startTime; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + public function getMaxSteps() + { + $phabelReturn = $this->max; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + public function getProgress() + { + $phabelReturn = $this->step; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + private function getStepWidth() + { + $phabelReturn = $this->stepWidth; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + public function getProgressPercent() + { + $phabelReturn = $this->percent; + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } + public function getBarOffset() + { + $phabelReturn = \floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (\min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth); + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } + public function getEstimated() + { + if (!$this->step) { + $phabelReturn = 0; + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \round((\time() - $this->startTime) / $this->step * $this->max); + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } + public function getRemaining() + { + if (!$this->step) { + $phabelReturn = 0; + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \round((\time() - $this->startTime) / $this->step * ($this->max - $this->step)); + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } + public function setBarWidth($size) + { + if (!\is_int($size)) { + if (!(\is_bool($size) || \is_numeric($size))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($size) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($size) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $size = (int) $size; + } + } + $this->barWidth = \max(1, $size); + } + public function getBarWidth() + { + $phabelReturn = $this->barWidth; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + public function setBarCharacter($char) + { + if (!\is_string($char)) { + if (!(\is_string($char) || \is_object($char) && \method_exists($char, '__toString') || (\is_bool($char) || \is_numeric($char)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($char) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($char) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $char = (string) $char; + } + } + $this->barChar = $char; + } + public function getBarCharacter() + { + if (null === $this->barChar) { + $phabelReturn = $this->max ? '=' : $this->emptyBarChar; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = $this->barChar; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function setEmptyBarCharacter($char) + { + if (!\is_string($char)) { + if (!(\is_string($char) || \is_object($char) && \method_exists($char, '__toString') || (\is_bool($char) || \is_numeric($char)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($char) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($char) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $char = (string) $char; + } + } + $this->emptyBarChar = $char; + } + public function getEmptyBarCharacter() + { + $phabelReturn = $this->emptyBarChar; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function setProgressCharacter($char) + { + if (!\is_string($char)) { + if (!(\is_string($char) || \is_object($char) && \method_exists($char, '__toString') || (\is_bool($char) || \is_numeric($char)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($char) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($char) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $char = (string) $char; + } + } + $this->progressChar = $char; + } + public function getProgressCharacter() + { + $phabelReturn = $this->progressChar; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function setFormat($format) + { + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $format = (string) $format; + } + } + $this->format = null; + $this->internalFormat = $format; + } + /** + * Sets the redraw frequency. + * + * @param int|null $freq The frequency in steps + */ + public function setRedrawFrequency($freq) + { + if (!\is_null($freq)) { + if (!\is_int($freq)) { + if (!(\is_bool($freq) || \is_numeric($freq))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($freq) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($freq) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $freq = (int) $freq; + } + } + } + $this->redrawFreq = null !== $freq ? \max(1, $freq) : null; + } + public function minSecondsBetweenRedraws($seconds) + { + if (!\is_float($seconds)) { + if (!(\is_bool($seconds) || \is_numeric($seconds))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($seconds) must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($seconds) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $seconds = (double) $seconds; + } + } + $this->minSecondsBetweenRedraws = $seconds; + } + public function maxSecondsBetweenRedraws($seconds) + { + if (!\is_float($seconds)) { + if (!(\is_bool($seconds) || \is_numeric($seconds))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($seconds) must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($seconds) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $seconds = (double) $seconds; + } + } + $this->maxSecondsBetweenRedraws = $seconds; + } + /** + * Returns an iterator that will automatically update the progress bar when iterated. + * + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable + */ + public function iterate($iterable, $max = null) + { + if (!(\is_array($iterable) || $iterable instanceof \Traversable)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($iterable) must be of type iterable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($iterable) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_null($max)) { + if (!\is_int($max)) { + if (!(\is_bool($max) || \is_numeric($max))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($max) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($max) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $max = (int) $max; + } + } + } + $this->start(isset($max) ? $max : (\is_countable($iterable) ? \count($iterable) : 0)); + foreach ($iterable as $key => $value) { + (yield $key => $value); + $this->advance(); + } + $this->finish(); + } + /** + * Starts the progress output. + * + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged + */ + public function start($max = null) + { + if (!\is_null($max)) { + if (!\is_int($max)) { + if (!(\is_bool($max) || \is_numeric($max))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($max) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($max) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $max = (int) $max; + } + } + } + $this->startTime = \time(); + $this->step = 0; + $this->percent = 0.0; + if (null !== $max) { + $this->setMaxSteps($max); + } + $this->display(); + } + /** + * Advances the progress output X steps. + * + * @param int $step Number of steps to advance + */ + public function advance($step = 1) + { + if (!\is_int($step)) { + if (!(\is_bool($step) || \is_numeric($step))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($step) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($step) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $step = (int) $step; + } + } + $this->setProgress($this->step + $step); + } + /** + * Sets whether to overwrite the progressbar, false for new line. + */ + public function setOverwrite($overwrite) + { + if (!\is_bool($overwrite)) { + if (!(\is_bool($overwrite) || \is_numeric($overwrite) || \is_string($overwrite))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($overwrite) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($overwrite) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $overwrite = (bool) $overwrite; + } + } + $this->overwrite = $overwrite; + } + public function setProgress($step) + { + if (!\is_int($step)) { + if (!(\is_bool($step) || \is_numeric($step))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($step) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($step) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $step = (int) $step; + } + } + if ($this->max && $step > $this->max) { + $this->max = $step; + } elseif ($step < 0) { + $step = 0; + } + $redrawFreq = isset($this->redrawFreq) ? $this->redrawFreq : ($this->max ?: 10) / 10; + $prevPeriod = (int) ($this->step / $redrawFreq); + $currPeriod = (int) ($step / $redrawFreq); + $this->step = $step; + $this->percent = $this->max ? (float) $this->step / $this->max : 0; + $timeInterval = \microtime(\true) - $this->lastWriteTime; + // Draw regardless of other limits + if ($this->max === $step) { + $this->display(); + return; + } + // Throttling + if ($timeInterval < $this->minSecondsBetweenRedraws) { + return; + } + // Draw each step period, but not too late + if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) { + $this->display(); + } + } + public function setMaxSteps($max) + { + if (!\is_int($max)) { + if (!(\is_bool($max) || \is_numeric($max))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($max) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($max) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $max = (int) $max; + } + } + $this->format = null; + $this->max = \max(0, $max); + $this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4; + } + /** + * Finishes the progress output. + */ + public function finish() + { + if (!$this->max) { + $this->max = $this->step; + } + if ($this->step === $this->max && !$this->overwrite) { + // prevent double 100% output + return; + } + $this->setProgress($this->max); + } + /** + * Outputs the current progress string. + */ + public function display() + { + if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { + return; + } + if (null === $this->format) { + $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); + } + $this->overwrite($this->buildLine()); + } + /** + * Removes the progress bar from the current line. + * + * This is useful if you wish to write some output + * while a progress bar is running. + * Call display() to show the progress bar again. + */ + public function clear() + { + if (!$this->overwrite) { + return; + } + if (null === $this->format) { + $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); + } + $this->overwrite(''); + } + private function setRealFormat($format) + { + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $format = (string) $format; + } + } + // try to use the _nomax variant if available + if (!$this->max && null !== self::getFormatDefinition($format . '_nomax')) { + $this->format = self::getFormatDefinition($format . '_nomax'); + } elseif (null !== self::getFormatDefinition($format)) { + $this->format = self::getFormatDefinition($format); + } else { + $this->format = $format; + } + $this->formatLineCount = \substr_count($this->format, "\n"); + } + /** + * Overwrites a previous message to the output. + */ + private function overwrite($message) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if ($this->previousMessage === $message) { + return; + } + $originalMessage = $message; + if ($this->overwrite) { + if (null !== $this->previousMessage) { + if ($this->output instanceof ConsoleSectionOutput) { + $messageLines = \explode("\n", $message); + $lineCount = \count($messageLines); + foreach ($messageLines as $messageLine) { + $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine)); + if ($messageLineLength > $this->terminal->getWidth()) { + $lineCount += \floor($messageLineLength / $this->terminal->getWidth()); + } + } + $this->output->clear($lineCount); + } else { + if ($this->formatLineCount > 0) { + $this->cursor->moveUp($this->formatLineCount); + } + $this->cursor->moveToColumn(1); + $this->cursor->clearLine(); + } + } + } elseif ($this->step > 0) { + $message = \PHP_EOL . $message; + } + $this->previousMessage = $originalMessage; + $this->lastWriteTime = \microtime(\true); + $this->output->write($message); + ++$this->writeCount; + } + private function determineBestFormat() + { + switch ($this->output->getVerbosity()) { + // OutputInterface::VERBOSITY_QUIET: display is disabled anyway + case OutputInterface::VERBOSITY_VERBOSE: + $phabelReturn = $this->max ? self::FORMAT_VERBOSE : self::FORMAT_VERBOSE_NOMAX; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case OutputInterface::VERBOSITY_VERY_VERBOSE: + $phabelReturn = $this->max ? self::FORMAT_VERY_VERBOSE : self::FORMAT_VERY_VERBOSE_NOMAX; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case OutputInterface::VERBOSITY_DEBUG: + $phabelReturn = $this->max ? self::FORMAT_DEBUG : self::FORMAT_DEBUG_NOMAX; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + default: + $phabelReturn = $this->max ? self::FORMAT_NORMAL : self::FORMAT_NORMAL_NOMAX; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + private static function initPlaceholderFormatters() + { + $phabelReturn = ['bar' => function (self $bar, OutputInterface $output) { + $completeBars = $bar->getBarOffset(); + $display = \str_repeat($bar->getBarCharacter(), $completeBars); + if ($completeBars < $bar->getBarWidth()) { + $emptyBars = $bar->getBarWidth() - $completeBars - Helper::length(Helper::removeDecoration($output->getFormatter(), $bar->getProgressCharacter())); + $display .= $bar->getProgressCharacter() . \str_repeat($bar->getEmptyBarCharacter(), $emptyBars); + } + return $display; + }, 'elapsed' => function (self $bar) { + return Helper::formatTime(\time() - $bar->getStartTime()); + }, 'remaining' => function (self $bar) { + if (!$bar->getMaxSteps()) { + throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.'); + } + return Helper::formatTime($bar->getRemaining()); + }, 'estimated' => function (self $bar) { + if (!$bar->getMaxSteps()) { + throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.'); + } + return Helper::formatTime($bar->getEstimated()); + }, 'memory' => function (self $bar) { + return Helper::formatMemory(\memory_get_usage(\true)); + }, 'current' => function (self $bar) { + return \str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT); + }, 'max' => function (self $bar) { + return $bar->getMaxSteps(); + }, 'percent' => function (self $bar) { + return \floor($bar->getProgressPercent() * 100); + }]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private static function initFormats() + { + $phabelReturn = [self::FORMAT_NORMAL => ' %current%/%max% [%bar%] %percent:3s%%', self::FORMAT_NORMAL_NOMAX => ' %current% [%bar%]', self::FORMAT_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%', self::FORMAT_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%', self::FORMAT_VERY_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%', self::FORMAT_VERY_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%', self::FORMAT_DEBUG => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%', self::FORMAT_DEBUG_NOMAX => ' %current% [%bar%] %elapsed:6s% %memory:6s%']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function buildLine() + { + $regex = "{%([a-z\\-_]+)(?:\\:([^%]+))?%}i"; + $callback = function ($matches) { + if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) { + $text = $formatter($this, $this->output); + } elseif (isset($this->messages[$matches[1]])) { + $text = $this->messages[$matches[1]]; + } else { + return $matches[0]; + } + if (isset($matches[2])) { + $text = \sprintf('%' . $matches[2], $text); + } + return $text; + }; + $line = \preg_replace_callback($regex, $callback, $this->format); + // gets string length for each sub line with multiline format + $linesLength = \array_map(function ($subLine) { + return Helper::width(Helper::removeDecoration($this->output->getFormatter(), \rtrim($subLine, "\r"))); + }, \explode("\n", $line)); + $linesWidth = \max($linesLength); + $terminalWidth = $this->terminal->getWidth(); + if ($linesWidth <= $terminalWidth) { + $phabelReturn = $line; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth); + $phabelReturn = \preg_replace_callback($regex, $callback, $this->format); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Helper/ProgressIndicator.php b/vendor-bundle/symfony/console/Helper/ProgressIndicator.php new file mode 100644 index 000000000..cd8cc0ceb --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/ProgressIndicator.php @@ -0,0 +1,312 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Exception\LogicException; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Kevin Bond + */ +class ProgressIndicator +{ + private $output; + private $startTime; + private $format; + private $message; + private $indicatorValues; + private $indicatorCurrent; + private $indicatorChangeInterval; + private $indicatorUpdateTime; + private $started = \false; + private static $formatters; + private static $formats; + /** + * @param int $indicatorChangeInterval Change interval in milliseconds + * @param array|null $indicatorValues Animated indicator characters + */ + public function __construct(OutputInterface $output, $format = null, $indicatorChangeInterval = 100, array $indicatorValues = null) + { + if (!\is_null($format)) { + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($format) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $format = (string) $format; + } + } + } + if (!\is_int($indicatorChangeInterval)) { + if (!(\is_bool($indicatorChangeInterval) || \is_numeric($indicatorChangeInterval))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($indicatorChangeInterval) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($indicatorChangeInterval) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $indicatorChangeInterval = (int) $indicatorChangeInterval; + } + } + $this->output = $output; + if (null === $format) { + $format = $this->determineBestFormat(); + } + if (null === $indicatorValues) { + $indicatorValues = ['-', '\\', '|', '/']; + } + $indicatorValues = \array_values($indicatorValues); + if (2 > \count($indicatorValues)) { + throw new InvalidArgumentException('Must have at least 2 indicator value characters.'); + } + $this->format = self::getFormatDefinition($format); + $this->indicatorChangeInterval = $indicatorChangeInterval; + $this->indicatorValues = $indicatorValues; + $this->startTime = \time(); + } + /** + * Sets the current indicator message. + */ + public function setMessage($message) + { + if (!\is_null($message)) { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + } + $this->message = $message; + $this->display(); + } + /** + * Starts the indicator output. + */ + public function start($message) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if ($this->started) { + throw new LogicException('Progress indicator already started.'); + } + $this->message = $message; + $this->started = \true; + $this->startTime = \time(); + $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval; + $this->indicatorCurrent = 0; + $this->display(); + } + /** + * Advances the indicator. + */ + public function advance() + { + if (!$this->started) { + throw new LogicException('Progress indicator has not yet been started.'); + } + if (!$this->output->isDecorated()) { + return; + } + $currentTime = $this->getCurrentTimeInMilliseconds(); + if ($currentTime < $this->indicatorUpdateTime) { + return; + } + $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval; + ++$this->indicatorCurrent; + $this->display(); + } + /** + * Finish the indicator with message. + * + * @param $message + */ + public function finish($message) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!$this->started) { + throw new LogicException('Progress indicator has not yet been started.'); + } + $this->message = $message; + $this->display(); + $this->output->writeln(''); + $this->started = \false; + } + /** + * Gets the format for a given name. + * + * @return string|null A format string + */ + public static function getFormatDefinition($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!self::$formats) { + self::$formats = self::initFormats(); + } + return isset(self::$formats[$name]) ? self::$formats[$name] : null; + } + /** + * Sets a placeholder formatter for a given name. + * + * This method also allow you to override an existing placeholder. + */ + public static function setPlaceholderFormatterDefinition($name, callable $callable) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!self::$formatters) { + self::$formatters = self::initPlaceholderFormatters(); + } + self::$formatters[$name] = $callable; + } + /** + * Gets the placeholder formatter for a given name (including the delimiter char like %). + * + * @return callable|null A PHP callable + */ + public static function getPlaceholderFormatterDefinition($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!self::$formatters) { + self::$formatters = self::initPlaceholderFormatters(); + } + return isset(self::$formatters[$name]) ? self::$formatters[$name] : null; + } + private function display() + { + if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { + return; + } + $this->overwrite(\preg_replace_callback("{%([a-z\\-_]+)(?:\\:([^%]+))?%}i", function ($matches) { + if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) { + return $formatter($this); + } + return $matches[0]; + }, isset($this->format) ? $this->format : '')); + } + private function determineBestFormat() + { + switch ($this->output->getVerbosity()) { + // OutputInterface::VERBOSITY_QUIET: display is disabled anyway + case OutputInterface::VERBOSITY_VERBOSE: + $phabelReturn = $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case OutputInterface::VERBOSITY_VERY_VERBOSE: + case OutputInterface::VERBOSITY_DEBUG: + $phabelReturn = $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + default: + $phabelReturn = $this->output->isDecorated() ? 'normal' : 'normal_no_ansi'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** + * Overwrites a previous message to the output. + */ + private function overwrite($message) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if ($this->output->isDecorated()) { + $this->output->write("\r\x1b[2K"); + $this->output->write($message); + } else { + $this->output->writeln($message); + } + } + private function getCurrentTimeInMilliseconds() + { + $phabelReturn = \round(\microtime(\true) * 1000); + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } + private static function initPlaceholderFormatters() + { + $phabelReturn = ['indicator' => function (self $indicator) { + return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)]; + }, 'message' => function (self $indicator) { + return $indicator->message; + }, 'elapsed' => function (self $indicator) { + return Helper::formatTime(\time() - $indicator->startTime); + }, 'memory' => function () { + return Helper::formatMemory(\memory_get_usage(\true)); + }]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private static function initFormats() + { + $phabelReturn = ['normal' => ' %indicator% %message%', 'normal_no_ansi' => ' %message%', 'verbose' => ' %indicator% %message% (%elapsed:6s%)', 'verbose_no_ansi' => ' %message% (%elapsed:6s%)', 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)', 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Helper/QuestionHelper.php b/vendor-bundle/symfony/console/Helper/QuestionHelper.php new file mode 100644 index 000000000..7c4d66b18 --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/QuestionHelper.php @@ -0,0 +1,638 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Cursor; +use Phabel\Symfony\Component\Console\Exception\MissingInputException; +use Phabel\Symfony\Component\Console\Exception\RuntimeException; +use Phabel\Symfony\Component\Console\Formatter\OutputFormatter; +use Phabel\Symfony\Component\Console\Formatter\OutputFormatterStyle; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Input\StreamableInputInterface; +use Phabel\Symfony\Component\Console\Output\ConsoleOutputInterface; +use Phabel\Symfony\Component\Console\Output\ConsoleSectionOutput; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +use Phabel\Symfony\Component\Console\Question\ChoiceQuestion; +use Phabel\Symfony\Component\Console\Question\Question; +use Phabel\Symfony\Component\Console\Terminal; +use function Phabel\Symfony\Component\String\s; +/** + * The QuestionHelper class provides helpers to interact with the user. + * + * @author Fabien Potencier + */ +class QuestionHelper extends Helper +{ + private $inputStream; + private static $shell; + private static $stty = \true; + private static $stdinIsInteractive; + /** + * Asks a question to the user. + * + * @return mixed The user answer + * + * @throws RuntimeException If there is no data to read in the input stream + */ + public function ask(InputInterface $input, OutputInterface $output, Question $question) + { + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + if (!$input->isInteractive()) { + return $this->getDefaultAnswer($question); + } + if ($input instanceof StreamableInputInterface && ($stream = $input->getStream())) { + $this->inputStream = $stream; + } + try { + if (!$question->getValidator()) { + return $this->doAsk($output, $question); + } + $interviewer = function () use($output, $question) { + return $this->doAsk($output, $question); + }; + return $this->validateAttempts($interviewer, $output, $question); + } catch (MissingInputException $exception) { + $input->setInteractive(\false); + if (null === ($fallbackOutput = $this->getDefaultAnswer($question))) { + throw $exception; + } + return $fallbackOutput; + } + } + /** + * {@inheritdoc} + */ + public function getName() + { + return 'question'; + } + /** + * Prevents usage of stty. + */ + public static function disableStty() + { + self::$stty = \false; + } + /** + * Asks the question to the user. + * + * @return mixed + * + * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden + */ + private function doAsk(OutputInterface $output, Question $question) + { + $this->writePrompt($output, $question); + $inputStream = $this->inputStream ?: \STDIN; + $autocomplete = $question->getAutocompleterCallback(); + if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) { + $ret = \false; + if ($question->isHidden()) { + try { + $hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable()); + $ret = $question->isTrimmable() ? \trim($hiddenResponse) : $hiddenResponse; + } catch (RuntimeException $e) { + if (!$question->isHiddenFallback()) { + throw $e; + } + } + } + if (\false === $ret) { + $ret = $this->readInput($inputStream, $question); + if (\false === $ret) { + throw new MissingInputException('Aborted.'); + } + if ($question->isTrimmable()) { + $ret = \trim($ret); + } + } + } else { + $autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete); + $ret = $question->isTrimmable() ? \trim($autocomplete) : $autocomplete; + } + if ($output instanceof ConsoleSectionOutput) { + $output->addContent($ret); + } + $ret = \strlen($ret) > 0 ? $ret : $question->getDefault(); + if ($normalizer = $question->getNormalizer()) { + return $normalizer($ret); + } + return $ret; + } + /** + * @return mixed + */ + private function getDefaultAnswer(Question $question) + { + $default = $question->getDefault(); + if (null === $default) { + return $default; + } + if ($validator = $question->getValidator()) { + return \call_user_func($question->getValidator(), $default); + } elseif ($question instanceof ChoiceQuestion) { + $choices = $question->getChoices(); + if (!$question->isMultiselect()) { + return isset($choices[$default]) ? $choices[$default] : $default; + } + $default = \explode(',', $default); + foreach ($default as $k => $v) { + $v = $question->isTrimmable() ? \trim($v) : $v; + $default[$k] = isset($choices[$v]) ? $choices[$v] : $v; + } + } + return $default; + } + /** + * Outputs the question prompt. + */ + protected function writePrompt(OutputInterface $output, Question $question) + { + $message = $question->getQuestion(); + if ($question instanceof ChoiceQuestion) { + $output->writeln(\array_merge([$question->getQuestion()], $this->formatChoiceQuestionChoices($question, 'info'))); + $message = $question->getPrompt(); + } + $output->write($message); + } + /** + * @return string[] + */ + protected function formatChoiceQuestionChoices(ChoiceQuestion $question, $tag) + { + if (!\is_string($tag)) { + if (!(\is_string($tag) || \is_object($tag) && \method_exists($tag, '__toString') || (\is_bool($tag) || \is_numeric($tag)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($tag) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($tag) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $tag = (string) $tag; + } + } + $messages = []; + $maxWidth = \max(\array_map('self::width', \array_keys($choices = $question->getChoices()))); + foreach ($choices as $key => $value) { + $padding = \str_repeat(' ', $maxWidth - self::width($key)); + $messages[] = \sprintf(" [<{$tag}>%s{$padding}] %s", $key, $value); + } + return $messages; + } + /** + * Outputs an error message. + */ + protected function writeError(OutputInterface $output, \Exception $error) + { + if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) { + $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'); + } else { + $message = '' . $error->getMessage() . ''; + } + $output->writeln($message); + } + /** + * Autocompletes a question. + * + * @param resource $inputStream + */ + private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete) + { + $cursor = new Cursor($output, $inputStream); + $fullChoice = ''; + $ret = ''; + $i = 0; + $ofs = -1; + $matches = $autocomplete($ret); + $numMatches = \count($matches); + $sttyMode = \shell_exec('stty -g'); + // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead) + \shell_exec('stty -icanon -echo'); + // Add highlighted text style + $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white')); + // Read a keypress + while (!\feof($inputStream)) { + $c = \fread($inputStream, 1); + // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false. + if (\false === $c || '' === $ret && '' === $c && null === $question->getDefault()) { + \shell_exec(\sprintf('stty %s', $sttyMode)); + throw new MissingInputException('Aborted.'); + } elseif ("" === $c) { + // Backspace Character + if (0 === $numMatches && 0 !== $i) { + --$i; + $cursor->moveLeft(s($fullChoice)->slice(-1)->width(\false)); + $fullChoice = self::substr($fullChoice, 0, $i); + } + if (0 === $i) { + $ofs = -1; + $matches = $autocomplete($ret); + $numMatches = \count($matches); + } else { + $numMatches = 0; + } + // Pop the last character off the end of our string + $ret = self::substr($ret, 0, $i); + } elseif ("\x1b" === $c) { + // Did we read an escape sequence? + $c .= \fread($inputStream, 2); + // A = Up Arrow. B = Down Arrow + if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) { + if ('A' === $c[2] && -1 === $ofs) { + $ofs = 0; + } + if (0 === $numMatches) { + continue; + } + $ofs += 'A' === $c[2] ? -1 : 1; + $ofs = ($numMatches + $ofs) % $numMatches; + } + } elseif (\ord($c) < 32) { + if ("\t" === $c || "\n" === $c) { + if ($numMatches > 0 && -1 !== $ofs) { + $ret = (string) $matches[$ofs]; + // Echo out remaining chars for current match + $remainingCharacters = \substr($ret, \strlen(\trim($this->mostRecentlyEnteredValue($fullChoice)))); + $output->write($remainingCharacters); + $fullChoice .= $remainingCharacters; + $i = \false === ($encoding = \mb_detect_encoding($fullChoice, null, \true)) ? \strlen($fullChoice) : \mb_strlen($fullChoice, $encoding); + $matches = \array_filter($autocomplete($ret), function ($match) use($ret) { + return '' === $ret || \str_starts_with($match, $ret); + }); + $numMatches = \count($matches); + $ofs = -1; + } + if ("\n" === $c) { + $output->write($c); + break; + } + $numMatches = 0; + } + continue; + } else { + if ("\x80" <= $c) { + $c .= \fread($inputStream, ["\xc0" => 1, "\xd0" => 1, "\xe0" => 2, "\xf0" => 3][$c & "\xf0"]); + } + $output->write($c); + $ret .= $c; + $fullChoice .= $c; + ++$i; + $tempRet = $ret; + if ($question instanceof ChoiceQuestion && $question->isMultiselect()) { + $tempRet = $this->mostRecentlyEnteredValue($fullChoice); + } + $numMatches = 0; + $ofs = 0; + foreach ($autocomplete($ret) as $value) { + // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) + if (\str_starts_with($value, $tempRet)) { + $matches[$numMatches++] = $value; + } + } + } + $cursor->clearLineAfter(); + if ($numMatches > 0 && -1 !== $ofs) { + $cursor->savePosition(); + // Write highlighted text, complete the partially entered response + $charactersEntered = \strlen(\trim($this->mostRecentlyEnteredValue($fullChoice))); + $output->write('' . OutputFormatter::escapeTrailingBackslash(\substr($matches[$ofs], $charactersEntered)) . ''); + $cursor->restorePosition(); + } + } + // Reset stty so it behaves normally again + \shell_exec(\sprintf('stty %s', $sttyMode)); + $phabelReturn = $fullChoice; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + private function mostRecentlyEnteredValue($entered) + { + if (!\is_string($entered)) { + if (!(\is_string($entered) || \is_object($entered) && \method_exists($entered, '__toString') || (\is_bool($entered) || \is_numeric($entered)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($entered) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($entered) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $entered = (string) $entered; + } + } + // Determine the most recent value that the user entered + if (!\str_contains($entered, ',')) { + $phabelReturn = $entered; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $choices = \explode(',', $entered); + if ('' !== ($lastChoice = \trim($choices[\count($choices) - 1]))) { + $phabelReturn = $lastChoice; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = $entered; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets a hidden response from user. + * + * @param resource $inputStream The handler resource + * @param bool $trimmable Is the answer trimmable + * + * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden + */ + private function getHiddenResponse(OutputInterface $output, $inputStream, $trimmable = \true) + { + if (!\is_bool($trimmable)) { + if (!(\is_bool($trimmable) || \is_numeric($trimmable) || \is_string($trimmable))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($trimmable) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($trimmable) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $trimmable = (bool) $trimmable; + } + } + if ('\\' === \DIRECTORY_SEPARATOR) { + $exe = __DIR__ . '/../Resources/bin/hiddeninput.exe'; + // handle code running from a phar + if ('phar:' === \substr(__FILE__, 0, 5)) { + $tmpExe = \sys_get_temp_dir() . '/hiddeninput.exe'; + \copy($exe, $tmpExe); + $exe = $tmpExe; + } + $sExec = \shell_exec('"' . $exe . '"'); + $value = $trimmable ? \rtrim($sExec) : $sExec; + $output->writeln(''); + if (isset($tmpExe)) { + \unlink($tmpExe); + } + $phabelReturn = $value; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (self::$stty && Terminal::hasSttyAvailable()) { + $sttyMode = \shell_exec('stty -g'); + \shell_exec('stty -echo'); + } elseif ($this->isInteractiveInput($inputStream)) { + throw new RuntimeException('Unable to hide the response.'); + } + $value = \fgets($inputStream, 4096); + if (self::$stty && Terminal::hasSttyAvailable()) { + \shell_exec(\sprintf('stty %s', $sttyMode)); + } + if (\false === $value) { + throw new MissingInputException('Aborted.'); + } + if ($trimmable) { + $value = \trim($value); + } + $output->writeln(''); + $phabelReturn = $value; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Validates an attempt. + * + * @param callable $interviewer A callable that will ask for a question and return the result + * + * @return mixed The validated response + * + * @throws \Exception In case the max number of attempts has been reached and no valid response has been given + */ + private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question) + { + $error = null; + $attempts = $question->getMaxAttempts(); + while (null === $attempts || $attempts--) { + if (null !== $error) { + $this->writeError($output, $error); + } + try { + $phabel_b3555919d25e5efd = $question->getValidator(); + return $phabel_b3555919d25e5efd($interviewer()); + } catch (RuntimeException $e) { + throw $e; + } catch (\Exception $error) { + } + } + throw $error; + } + private function isInteractiveInput($inputStream) + { + if ('php://stdin' !== (NULL !== ($phabel_376920cdae0760e0 = \stream_get_meta_data($inputStream)) && isset($phabel_376920cdae0760e0['uri']) ? $phabel_376920cdae0760e0['uri'] : null)) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if (null !== self::$stdinIsInteractive) { + $phabelReturn = self::$stdinIsInteractive; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if (\function_exists('stream_isatty')) { + $phabelReturn = self::$stdinIsInteractive = \stream_isatty(\fopen('php://stdin', 'r')); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if (\function_exists('posix_isatty')) { + $phabelReturn = self::$stdinIsInteractive = \posix_isatty(\fopen('php://stdin', 'r')); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if (!\function_exists('exec')) { + $phabelReturn = self::$stdinIsInteractive = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + \exec('stty 2> /dev/null', $output, $status); + $phabelReturn = self::$stdinIsInteractive = 1 !== $status; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Reads one or more lines of input and returns what is read. + * + * @param resource $inputStream The handler resource + * @param Question $question The question being asked + * + * @return string|false The input received, false in case input could not be read + */ + private function readInput($inputStream, Question $question) + { + if (!$question->isMultiline()) { + $cp = $this->setIOCodepage(); + $ret = \fgets($inputStream, 4096); + return $this->resetIOCodepage($cp, $ret); + } + $multiLineStreamReader = $this->cloneInputStream($inputStream); + if (null === $multiLineStreamReader) { + return \false; + } + $ret = ''; + $cp = $this->setIOCodepage(); + while (\false !== ($char = \fgetc($multiLineStreamReader))) { + if (\PHP_EOL === "{$ret}{$char}") { + break; + } + $ret .= $char; + } + return $this->resetIOCodepage($cp, $ret); + } + /** + * Sets console I/O to the host code page. + * + * @return int Previous code page in IBM/EBCDIC format + */ + private function setIOCodepage() + { + if (\function_exists('sapi_windows_cp_set')) { + $cp = \sapi_windows_cp_get(); + \sapi_windows_cp_set(\sapi_windows_cp_get('oem')); + $phabelReturn = $cp; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = 0; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Sets console I/O to the specified code page and converts the user input. + * + * @param string|false $input + * + * @return string|false + */ + private function resetIOCodepage($cp, $input) + { + if (!\is_int($cp)) { + if (!(\is_bool($cp) || \is_numeric($cp))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($cp) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cp = (int) $cp; + } + } + if (0 !== $cp) { + \sapi_windows_cp_set($cp); + if (\false !== $input && '' !== $input) { + $input = \sapi_windows_cp_conv(\sapi_windows_cp_get('oem'), $cp, $input); + } + } + return $input; + } + /** + * Clones an input stream in order to act on one instance of the same + * stream without affecting the other instance. + * + * @param resource $inputStream The handler resource + * + * @return resource|null The cloned resource, null in case it could not be cloned + */ + private function cloneInputStream($inputStream) + { + $streamMetaData = \stream_get_meta_data($inputStream); + $seekable = isset($streamMetaData['seekable']) ? $streamMetaData['seekable'] : \false; + $mode = isset($streamMetaData['mode']) ? $streamMetaData['mode'] : 'rb'; + $uri = isset($streamMetaData['uri']) ? $streamMetaData['uri'] : null; + if (null === $uri) { + return null; + } + $cloneStream = \fopen($uri, $mode); + // For seekable and writable streams, add all the same data to the + // cloned stream and then seek to the same offset. + if (\true === $seekable && !\in_array($mode, ['r', 'rb', 'rt'])) { + $offset = \ftell($inputStream); + \rewind($inputStream); + \stream_copy_to_stream($inputStream, $cloneStream); + \fseek($inputStream, $offset); + \fseek($cloneStream, $offset); + } + return $cloneStream; + } +} diff --git a/vendor-bundle/symfony/console/Helper/SymfonyQuestionHelper.php b/vendor-bundle/symfony/console/Helper/SymfonyQuestionHelper.php new file mode 100644 index 000000000..a0e7c540d --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/SymfonyQuestionHelper.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Formatter\OutputFormatter; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +use Phabel\Symfony\Component\Console\Question\ChoiceQuestion; +use Phabel\Symfony\Component\Console\Question\ConfirmationQuestion; +use Phabel\Symfony\Component\Console\Question\Question; +use Phabel\Symfony\Component\Console\Style\SymfonyStyle; +/** + * Symfony Style Guide compliant question helper. + * + * @author Kevin Bond + */ +class SymfonyQuestionHelper extends QuestionHelper +{ + /** + * {@inheritdoc} + */ + protected function writePrompt(OutputInterface $output, Question $question) + { + $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion()); + $default = $question->getDefault(); + if ($question->isMultiline()) { + $text .= \sprintf(' (press %s to continue)', $this->getEofShortcut()); + } + switch (\true) { + case null === $default: + $text = \sprintf(' %s:', $text); + break; + case $question instanceof ConfirmationQuestion: + $text = \sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); + break; + case $question instanceof ChoiceQuestion && $question->isMultiselect(): + $choices = $question->getChoices(); + $default = \explode(',', $default); + foreach ($default as $key => $value) { + $default[$key] = $choices[\trim($value)]; + } + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape(\implode(', ', $default))); + break; + case $question instanceof ChoiceQuestion: + $choices = $question->getChoices(); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape(isset($choices[$default]) ? $choices[$default] : $default)); + break; + default: + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); + } + $output->writeln($text); + $prompt = ' > '; + if ($question instanceof ChoiceQuestion) { + $output->writeln($this->formatChoiceQuestionChoices($question, 'comment')); + $prompt = $question->getPrompt(); + } + $output->write($prompt); + } + /** + * {@inheritdoc} + */ + protected function writeError(OutputInterface $output, \Exception $error) + { + if ($output instanceof SymfonyStyle) { + $output->newLine(); + $output->error($error->getMessage()); + return; + } + parent::writeError($output, $error); + } + private function getEofShortcut() + { + if ('Windows' === \PHP_OS_FAMILY) { + $phabelReturn = 'Ctrl+Z then Enter'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = 'Ctrl+D'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Helper/Table.php b/vendor-bundle/symfony/console/Helper/Table.php new file mode 100644 index 000000000..57d0f7cac --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/Table.php @@ -0,0 +1,979 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Exception\RuntimeException; +use Phabel\Symfony\Component\Console\Formatter\OutputFormatter; +use Phabel\Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface; +use Phabel\Symfony\Component\Console\Output\ConsoleSectionOutput; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * Provides helpers to display a table. + * + * @author Fabien Potencier + * @author Саша Стаменковић + * @author Abdellatif Ait boudad + * @author Max Grigorian + * @author Dany Maillard + */ +class Table +{ + const SEPARATOR_TOP = 0; + const SEPARATOR_TOP_BOTTOM = 1; + const SEPARATOR_MID = 2; + const SEPARATOR_BOTTOM = 3; + const BORDER_OUTSIDE = 0; + const BORDER_INSIDE = 1; + private $headerTitle; + private $footerTitle; + /** + * Table headers. + */ + private $headers = []; + /** + * Table rows. + */ + private $rows = []; + private $horizontal = \false; + /** + * Column widths cache. + */ + private $effectiveColumnWidths = []; + /** + * Number of columns cache. + * + * @var int + */ + private $numberOfColumns; + /** + * @var OutputInterface + */ + private $output; + /** + * @var TableStyle + */ + private $style; + /** + * @var array + */ + private $columnStyles = []; + /** + * User set column widths. + * + * @var array + */ + private $columnWidths = []; + private $columnMaxWidths = []; + private static $styles; + private $rendered = \false; + public function __construct(OutputInterface $output) + { + $this->output = $output; + if (!self::$styles) { + self::$styles = self::initStyles(); + } + $this->setStyle('default'); + } + /** + * Sets a style definition. + */ + public static function setStyleDefinition($name, TableStyle $style) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!self::$styles) { + self::$styles = self::initStyles(); + } + self::$styles[$name] = $style; + } + /** + * Gets a style definition by name. + * + * @return TableStyle + */ + public static function getStyleDefinition($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!self::$styles) { + self::$styles = self::initStyles(); + } + if (isset(self::$styles[$name])) { + return self::$styles[$name]; + } + throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); + } + /** + * Sets table style. + * + * @param TableStyle|string $name The style name or a TableStyle instance + * + * @return $this + */ + public function setStyle($name) + { + $this->style = $this->resolveStyle($name); + return $this; + } + /** + * Gets the current table style. + * + * @return TableStyle + */ + public function getStyle() + { + return $this->style; + } + /** + * Sets table column style. + * + * @param TableStyle|string $name The style name or a TableStyle instance + * + * @return $this + */ + public function setColumnStyle($columnIndex, $name) + { + if (!\is_int($columnIndex)) { + if (!(\is_bool($columnIndex) || \is_numeric($columnIndex))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($columnIndex) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($columnIndex) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $columnIndex = (int) $columnIndex; + } + } + $this->columnStyles[$columnIndex] = $this->resolveStyle($name); + return $this; + } + /** + * Gets the current style for a column. + * + * If style was not set, it returns the global table style. + * + * @return TableStyle + */ + public function getColumnStyle($columnIndex) + { + if (!\is_int($columnIndex)) { + if (!(\is_bool($columnIndex) || \is_numeric($columnIndex))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($columnIndex) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($columnIndex) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $columnIndex = (int) $columnIndex; + } + } + return isset($this->columnStyles[$columnIndex]) ? $this->columnStyles[$columnIndex] : $this->getStyle(); + } + /** + * Sets the minimum width of a column. + * + * @return $this + */ + public function setColumnWidth($columnIndex, $width) + { + if (!\is_int($columnIndex)) { + if (!(\is_bool($columnIndex) || \is_numeric($columnIndex))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($columnIndex) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($columnIndex) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $columnIndex = (int) $columnIndex; + } + } + if (!\is_int($width)) { + if (!(\is_bool($width) || \is_numeric($width))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($width) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($width) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $width = (int) $width; + } + } + $this->columnWidths[$columnIndex] = $width; + return $this; + } + /** + * Sets the minimum width of all columns. + * + * @return $this + */ + public function setColumnWidths(array $widths) + { + $this->columnWidths = []; + foreach ($widths as $index => $width) { + $this->setColumnWidth($index, $width); + } + return $this; + } + /** + * Sets the maximum width of a column. + * + * Any cell within this column which contents exceeds the specified width will be wrapped into multiple lines, while + * formatted strings are preserved. + * + * @return $this + */ + public function setColumnMaxWidth($columnIndex, $width) + { + if (!\is_int($columnIndex)) { + if (!(\is_bool($columnIndex) || \is_numeric($columnIndex))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($columnIndex) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($columnIndex) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $columnIndex = (int) $columnIndex; + } + } + if (!\is_int($width)) { + if (!(\is_bool($width) || \is_numeric($width))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($width) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($width) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $width = (int) $width; + } + } + if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) { + throw new \LogicException(\sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, \get_debug_type($this->output->getFormatter()))); + } + $this->columnMaxWidths[$columnIndex] = $width; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function setHeaders(array $headers) + { + $headers = \array_values($headers); + if (!empty($headers) && !\is_array($headers[0])) { + $headers = [$headers]; + } + $this->headers = $headers; + return $this; + } + public function setRows(array $rows) + { + $this->rows = []; + return $this->addRows($rows); + } + public function addRows(array $rows) + { + foreach ($rows as $row) { + $this->addRow($row); + } + return $this; + } + public function addRow($row) + { + if ($row instanceof TableSeparator) { + $this->rows[] = $row; + return $this; + } + if (!\is_array($row)) { + throw new InvalidArgumentException('A row must be an array or a TableSeparator instance.'); + } + $this->rows[] = \array_values($row); + return $this; + } + /** + * Adds a row to the table, and re-renders the table. + */ + public function appendRow($row) + { + if (!$this->output instanceof ConsoleSectionOutput) { + throw new RuntimeException(\sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); + } + if ($this->rendered) { + $this->output->clear($this->calculateRowCount()); + } + $this->addRow($row); + $this->render(); + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function setRow($column, array $row) + { + $this->rows[$column] = $row; + return $this; + } + public function setHeaderTitle($title) + { + if (!\is_null($title)) { + if (!\is_string($title)) { + if (!(\is_string($title) || \is_object($title) && \method_exists($title, '__toString') || (\is_bool($title) || \is_numeric($title)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($title) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($title) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $title = (string) $title; + } + } + } + $this->headerTitle = $title; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function setFooterTitle($title) + { + if (!\is_null($title)) { + if (!\is_string($title)) { + if (!(\is_string($title) || \is_object($title) && \method_exists($title, '__toString') || (\is_bool($title) || \is_numeric($title)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($title) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($title) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $title = (string) $title; + } + } + } + $this->footerTitle = $title; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function setHorizontal($horizontal = \true) + { + if (!\is_bool($horizontal)) { + if (!(\is_bool($horizontal) || \is_numeric($horizontal) || \is_string($horizontal))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($horizontal) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($horizontal) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $horizontal = (bool) $horizontal; + } + } + $this->horizontal = $horizontal; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Renders table to output. + * + * Example: + * + * +---------------+-----------------------+------------------+ + * | ISBN | Title | Author | + * +---------------+-----------------------+------------------+ + * | 99921-58-10-7 | Divine Comedy | Dante Alighieri | + * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | + * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | + * +---------------+-----------------------+------------------+ + */ + public function render() + { + $divider = new TableSeparator(); + if ($this->horizontal) { + $rows = []; + foreach (isset($this->headers[0]) ? $this->headers[0] : [] as $i => $header) { + $rows[$i] = [$header]; + foreach ($this->rows as $row) { + if ($row instanceof TableSeparator) { + continue; + } + if (isset($row[$i])) { + $rows[$i][] = $row[$i]; + } elseif ($rows[$i][0] instanceof TableCell && $rows[$i][0]->getColspan() >= 2) { + // Noop, there is a "title" + } else { + $rows[$i][] = null; + } + } + } + } else { + $rows = \array_merge($this->headers, [$divider], $this->rows); + } + $this->calculateNumberOfColumns($rows); + $rows = $this->buildTableRows($rows); + $this->calculateColumnsWidth($rows); + $isHeader = !$this->horizontal; + $isFirstRow = $this->horizontal; + $hasTitle = (bool) $this->headerTitle; + foreach ($rows as $row) { + if ($divider === $row) { + $isHeader = \false; + $isFirstRow = \true; + continue; + } + if ($row instanceof TableSeparator) { + $this->renderRowSeparator(); + continue; + } + if (!$row) { + continue; + } + if ($isHeader || $isFirstRow) { + $this->renderRowSeparator($isHeader ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null); + $isFirstRow = \false; + $hasTitle = \false; + } + if ($this->horizontal) { + $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat()); + } else { + $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat()); + } + } + $this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat()); + $this->cleanup(); + $this->rendered = \true; + } + /** + * Renders horizontal header separator. + * + * Example: + * + * +-----+-----------+-------+ + */ + private function renderRowSeparator($type = self::SEPARATOR_MID, $title = null, $titleFormat = null) + { + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + if (!\is_null($title)) { + if (!\is_string($title)) { + if (!(\is_string($title) || \is_object($title) && \method_exists($title, '__toString') || (\is_bool($title) || \is_numeric($title)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($title) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($title) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $title = (string) $title; + } + } + } + if (!\is_null($titleFormat)) { + if (!\is_string($titleFormat)) { + if (!(\is_string($titleFormat) || \is_object($titleFormat) && \method_exists($titleFormat, '__toString') || (\is_bool($titleFormat) || \is_numeric($titleFormat)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($titleFormat) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($titleFormat) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $titleFormat = (string) $titleFormat; + } + } + } + if (0 === ($count = $this->numberOfColumns)) { + return; + } + $borders = $this->style->getBorderChars(); + if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) { + return; + } + $crossings = $this->style->getCrossingChars(); + if (self::SEPARATOR_MID === $type) { + list($horizontal, $leftChar, $midChar, $rightChar) = [$borders[2], $crossings[8], $crossings[0], $crossings[4]]; + } elseif (self::SEPARATOR_TOP === $type) { + list($horizontal, $leftChar, $midChar, $rightChar) = [$borders[0], $crossings[1], $crossings[2], $crossings[3]]; + } elseif (self::SEPARATOR_TOP_BOTTOM === $type) { + list($horizontal, $leftChar, $midChar, $rightChar) = [$borders[0], $crossings[9], $crossings[10], $crossings[11]]; + } else { + list($horizontal, $leftChar, $midChar, $rightChar) = [$borders[0], $crossings[7], $crossings[6], $crossings[5]]; + } + $markup = $leftChar; + for ($column = 0; $column < $count; ++$column) { + $markup .= \str_repeat($horizontal, $this->effectiveColumnWidths[$column]); + $markup .= $column === $count - 1 ? $rightChar : $midChar; + } + if (null !== $title) { + $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = \sprintf($titleFormat, $title))); + $markupLength = Helper::width($markup); + if ($titleLength > ($limit = $markupLength - 4)) { + $titleLength = $limit; + $formatLength = Helper::width(Helper::removeDecoration($formatter, \sprintf($titleFormat, ''))); + $formattedTitle = \sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3) . '...'); + } + $titleStart = \intdiv($markupLength - $titleLength, 2); + if (\false === \mb_detect_encoding($markup, null, \true)) { + $markup = \substr_replace($markup, $formattedTitle, $titleStart, $titleLength); + } else { + $markup = \mb_substr($markup, 0, $titleStart) . $formattedTitle . \mb_substr($markup, $titleStart + $titleLength); + } + } + $this->output->writeln(\sprintf($this->style->getBorderFormat(), $markup)); + } + /** + * Renders vertical column separator. + */ + private function renderColumnSeparator($type = self::BORDER_OUTSIDE) + { + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + $borders = $this->style->getBorderChars(); + $phabelReturn = \sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Renders table row. + * + * Example: + * + * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | + */ + private function renderRow(array $row, $cellFormat, $firstCellFormat = null) + { + if (!\is_string($cellFormat)) { + if (!(\is_string($cellFormat) || \is_object($cellFormat) && \method_exists($cellFormat, '__toString') || (\is_bool($cellFormat) || \is_numeric($cellFormat)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($cellFormat) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cellFormat) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cellFormat = (string) $cellFormat; + } + } + if (!\is_null($firstCellFormat)) { + if (!\is_string($firstCellFormat)) { + if (!(\is_string($firstCellFormat) || \is_object($firstCellFormat) && \method_exists($firstCellFormat, '__toString') || (\is_bool($firstCellFormat) || \is_numeric($firstCellFormat)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($firstCellFormat) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($firstCellFormat) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $firstCellFormat = (string) $firstCellFormat; + } + } + } + $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE); + $columns = $this->getRowColumns($row); + $last = \count($columns) - 1; + foreach ($columns as $i => $column) { + if ($firstCellFormat && 0 === $i) { + $rowContent .= $this->renderCell($row, $column, $firstCellFormat); + } else { + $rowContent .= $this->renderCell($row, $column, $cellFormat); + } + $rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE); + } + $this->output->writeln($rowContent); + } + /** + * Renders table cell with padding. + */ + private function renderCell(array $row, $column, $cellFormat) + { + if (!\is_int($column)) { + if (!(\is_bool($column) || \is_numeric($column))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($column) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($column) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $column = (int) $column; + } + } + if (!\is_string($cellFormat)) { + if (!(\is_string($cellFormat) || \is_object($cellFormat) && \method_exists($cellFormat, '__toString') || (\is_bool($cellFormat) || \is_numeric($cellFormat)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($cellFormat) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cellFormat) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cellFormat = (string) $cellFormat; + } + } + $cell = isset($row[$column]) ? $row[$column] : ''; + $width = $this->effectiveColumnWidths[$column]; + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + // add the width of the following columns(numbers of colspan). + foreach (\range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) { + $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn]; + } + } + // str_pad won't work properly with multi-byte strings, we need to fix the padding + if (\false !== ($encoding = \mb_detect_encoding($cell, null, \true))) { + $width += \strlen($cell) - \mb_strwidth($cell, $encoding); + } + $style = $this->getColumnStyle($column); + if ($cell instanceof TableSeparator) { + $phabelReturn = \sprintf($style->getBorderFormat(), \str_repeat($style->getBorderChars()[2], $width)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell)); + $content = \sprintf($style->getCellRowContentFormat(), $cell); + $padType = $style->getPadType(); + if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) { + $isNotStyledByTag = !\preg_match('/^<(\\w+|(\\w+=[\\w,]+;?)*)>.+<\\/(\\w+|(\\w+=\\w+;?)*)?>$/', $cell); + if ($isNotStyledByTag) { + $cellFormat = $cell->getStyle()->getCellFormat(); + if (!\is_string($cellFormat)) { + $tag = \http_build_query($cell->getStyle()->getTagOptions(), '', ';'); + $cellFormat = '<' . $tag . '>%s'; + } + if (\strstr($content, '')) { + $content = \str_replace('', '', $content); + $width -= 3; + } + if (\strstr($content, '')) { + $content = \str_replace('', '', $content); + $width -= \strlen(''); + } + } + $padType = $cell->getStyle()->getPadByAlign(); + } + $phabelReturn = \sprintf($cellFormat, \str_pad($content, $width, $style->getPaddingChar(), $padType)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Calculate number of columns for this table. + */ + private function calculateNumberOfColumns(array $rows) + { + $columns = [0]; + foreach ($rows as $row) { + if ($row instanceof TableSeparator) { + continue; + } + $columns[] = $this->getNumberOfColumns($row); + } + $this->numberOfColumns = \max($columns); + } + private function buildTableRows(array $rows) + { + /** @var WrappableOutputFormatterInterface $formatter */ + $formatter = $this->output->getFormatter(); + $unmergedRows = []; + for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) { + $rows = $this->fillNextRows($rows, $rowKey); + // Remove any new line breaks and replace it with a new line + foreach ($rows[$rowKey] as $column => $cell) { + $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1; + if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) { + $cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan); + } + if (!\strstr(isset($cell) ? $cell : '', "\n")) { + continue; + } + $escaped = \implode("\n", \array_map([OutputFormatter::class, 'escapeTrailingBackslash'], \explode("\n", $cell))); + $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped; + $lines = \explode("\n", \str_replace("\n", "\n", $cell)); + foreach ($lines as $lineKey => $line) { + if ($colspan > 1) { + $line = new TableCell($line, ['colspan' => $colspan]); + } + if (0 === $lineKey) { + $rows[$rowKey][$column] = $line; + } else { + if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) { + $unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey); + } + $unmergedRows[$rowKey][$lineKey][$column] = $line; + } + } + } + } + $phabelReturn = new TableRows(function () use($rows, $unmergedRows) { + foreach ($rows as $rowKey => $row) { + (yield $row instanceof TableSeparator ? $row : $this->fillCells($row)); + if (isset($unmergedRows[$rowKey])) { + foreach ($unmergedRows[$rowKey] as $row) { + (yield $row instanceof TableSeparator ? $row : $this->fillCells($row)); + } + } + } + }); + if (!$phabelReturn instanceof TableRows) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type TableRows, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function calculateRowCount() + { + $numberOfRows = \count(\iterator_to_array($this->buildTableRows(\array_merge($this->headers, [new TableSeparator()], $this->rows)))); + if ($this->headers) { + ++$numberOfRows; + // Add row for header separator + } + if (\count($this->rows) > 0) { + ++$numberOfRows; + // Add row for footer separator + } + $phabelReturn = $numberOfRows; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * fill rows that contains rowspan > 1. + * + * @throws InvalidArgumentException + */ + private function fillNextRows(array $rows, $line) + { + if (!\is_int($line)) { + if (!(\is_bool($line) || \is_numeric($line))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($line) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($line) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $line = (int) $line; + } + } + $unmergedRows = []; + foreach ($rows[$line] as $column => $cell) { + if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !(\is_object($cell) && \method_exists($cell, '__toString'))) { + throw new InvalidArgumentException(\sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', \get_debug_type($cell))); + } + if ($cell instanceof TableCell && $cell->getRowspan() > 1) { + $nbLines = $cell->getRowspan() - 1; + $lines = [$cell]; + if (\strstr($cell, "\n")) { + $lines = \explode("\n", \str_replace("\n", "\n", $cell)); + $nbLines = \count($lines) > $nbLines ? \substr_count($cell, "\n") : $nbLines; + $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); + unset($lines[0]); + } + // create a two dimensional array (rowspan x colspan) + $unmergedRows = \array_replace_recursive(\array_fill($line + 1, $nbLines, []), $unmergedRows); + foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { + $value = isset($lines[$unmergedRowKey - $line]) ? $lines[$unmergedRowKey - $line] : ''; + $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); + if ($nbLines === $unmergedRowKey - $line) { + break; + } + } + } + } + foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { + // we need to know if $unmergedRow will be merged or inserted into $rows + if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && $this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns) { + foreach ($unmergedRow as $cellKey => $cell) { + // insert cell into row at cellKey position + \array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]); + } + } else { + $row = $this->copyRow($rows, $unmergedRowKey - 1); + foreach ($unmergedRow as $column => $cell) { + if (!empty($cell)) { + $row[$column] = $unmergedRow[$column]; + } + } + \array_splice($rows, $unmergedRowKey, 0, [$row]); + } + } + $phabelReturn = $rows; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * fill cells for a row that contains colspan > 1. + */ + private function fillCells($row) + { + if (!(\is_array($row) || $row instanceof \Traversable)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($row) must be of type iterable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($row) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + $newRow = []; + foreach ($row as $column => $cell) { + $newRow[] = $cell; + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + foreach (\range($column + 1, $column + $cell->getColspan() - 1) as $position) { + // insert empty value at column position + $newRow[] = ''; + } + } + } + return $newRow ?: $row; + } + private function copyRow(array $rows, $line) + { + if (!\is_int($line)) { + if (!(\is_bool($line) || \is_numeric($line))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($line) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($line) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $line = (int) $line; + } + } + $row = $rows[$line]; + foreach ($row as $cellKey => $cellValue) { + $row[$cellKey] = ''; + if ($cellValue instanceof TableCell) { + $row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]); + } + } + $phabelReturn = $row; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Gets number of columns by row. + */ + private function getNumberOfColumns(array $row) + { + $columns = \count($row); + foreach ($row as $column) { + $columns += $column instanceof TableCell ? $column->getColspan() - 1 : 0; + } + $phabelReturn = $columns; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets list of columns for the given row. + */ + private function getRowColumns(array $row) + { + $columns = \range(0, $this->numberOfColumns - 1); + foreach ($row as $cellKey => $cell) { + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + // exclude grouped columns. + $columns = \array_diff($columns, \range($cellKey + 1, $cellKey + $cell->getColspan() - 1)); + } + } + $phabelReturn = $columns; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Calculates columns widths. + */ + private function calculateColumnsWidth($rows) + { + if (!(\is_array($rows) || $rows instanceof \Traversable)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($rows) must be of type iterable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($rows) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + for ($column = 0; $column < $this->numberOfColumns; ++$column) { + $lengths = []; + foreach ($rows as $row) { + if ($row instanceof TableSeparator) { + continue; + } + foreach ($row as $i => $cell) { + if ($cell instanceof TableCell) { + $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell); + $textLength = Helper::width($textContent); + if ($textLength > 0) { + $contentColumns = \str_split($textContent, \ceil($textLength / $cell->getColspan())); + foreach ($contentColumns as $position => $content) { + $row[$i + $position] = $content; + } + } + } + } + $lengths[] = $this->getCellWidth($row, $column); + } + $this->effectiveColumnWidths[$column] = \max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2; + } + } + private function getColumnSeparatorWidth() + { + $phabelReturn = Helper::width(\sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + private function getCellWidth(array $row, $column) + { + if (!\is_int($column)) { + if (!(\is_bool($column) || \is_numeric($column))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($column) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($column) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $column = (int) $column; + } + } + $cellWidth = 0; + if (isset($row[$column])) { + $cell = $row[$column]; + $cellWidth = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $cell)); + } + $columnWidth = isset($this->columnWidths[$column]) ? $this->columnWidths[$column] : 0; + $cellWidth = \max($cellWidth, $columnWidth); + $phabelReturn = isset($this->columnMaxWidths[$column]) ? \min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Called after rendering to cleanup cache data. + */ + private function cleanup() + { + $this->effectiveColumnWidths = []; + $this->numberOfColumns = null; + } + private static function initStyles() + { + $borderless = new TableStyle(); + $borderless->setHorizontalBorderChars('=')->setVerticalBorderChars(' ')->setDefaultCrossingChar(' '); + $compact = new TableStyle(); + $compact->setHorizontalBorderChars('')->setVerticalBorderChars(' ')->setDefaultCrossingChar('')->setCellRowContentFormat('%s'); + $styleGuide = new TableStyle(); + $styleGuide->setHorizontalBorderChars('-')->setVerticalBorderChars(' ')->setDefaultCrossingChar(' ')->setCellHeaderFormat('%s'); + $box = (new TableStyle())->setHorizontalBorderChars('─')->setVerticalBorderChars('│')->setCrossingChars('┼', '┌', '┬', '┐', '┤', '┘', '┴', '└', '├'); + $boxDouble = (new TableStyle())->setHorizontalBorderChars('═', '─')->setVerticalBorderChars('║', '│')->setCrossingChars('┼', '╔', '╤', '╗', '╢', '╝', '╧', '╚', '╟', '╠', '╪', '╣'); + $phabelReturn = ['default' => new TableStyle(), 'borderless' => $borderless, 'compact' => $compact, 'symfony-style-guide' => $styleGuide, 'box' => $box, 'box-double' => $boxDouble]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function resolveStyle($name) + { + if ($name instanceof TableStyle) { + $phabelReturn = $name; + if (!$phabelReturn instanceof TableStyle) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type TableStyle, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if (isset(self::$styles[$name])) { + $phabelReturn = self::$styles[$name]; + if (!$phabelReturn instanceof TableStyle) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type TableStyle, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); + throw new \TypeError(__METHOD__ . '(): Return value must be of type TableStyle, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } +} diff --git a/vendor-bundle/symfony/console/Helper/TableCell.php b/vendor-bundle/symfony/console/Helper/TableCell.php new file mode 100644 index 000000000..d10728089 --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/TableCell.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * @author Abdellatif Ait boudad + */ +class TableCell +{ + private $value; + private $options = ['rowspan' => 1, 'colspan' => 1, 'style' => null]; + public function __construct($value = '', array $options = []) + { + if (!\is_string($value)) { + if (!(\is_string($value) || \is_object($value) && \method_exists($value, '__toString') || (\is_bool($value) || \is_numeric($value)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($value) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($value) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $value = (string) $value; + } + } + $this->value = $value; + // check option names + if ($diff = \array_diff(\array_keys($options), \array_keys($this->options))) { + throw new InvalidArgumentException(\sprintf('The TableCell does not support the following options: \'%s\'.', \implode('\', \'', $diff))); + } + if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) { + throw new InvalidArgumentException('The style option must be an instance of "TableCellStyle".'); + } + $this->options = \array_merge($this->options, $options); + } + /** + * Returns the cell value. + * + * @return string + */ + public function __toString() + { + return $this->value; + } + /** + * Gets number of colspan. + * + * @return int + */ + public function getColspan() + { + return (int) $this->options['colspan']; + } + /** + * Gets number of rowspan. + * + * @return int + */ + public function getRowspan() + { + return (int) $this->options['rowspan']; + } + public function getStyle() + { + $phabelReturn = $this->options['style']; + if (!($phabelReturn instanceof TableCellStyle || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?TableCellStyle, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Helper/TableCellStyle.php b/vendor-bundle/symfony/console/Helper/TableCellStyle.php new file mode 100644 index 000000000..442ad9745 --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/TableCellStyle.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * @author Yewhen Khoptynskyi + */ +class TableCellStyle +{ + const DEFAULT_ALIGN = 'left'; + private $options = ['fg' => 'default', 'bg' => 'default', 'options' => null, 'align' => self::DEFAULT_ALIGN, 'cellFormat' => null]; + private $tagOptions = ['fg', 'bg', 'options']; + private $alignMap = ['left' => \STR_PAD_RIGHT, 'center' => \STR_PAD_BOTH, 'right' => \STR_PAD_LEFT]; + public function __construct(array $options = []) + { + if ($diff = \array_diff(\array_keys($options), \array_keys($this->options))) { + throw new InvalidArgumentException(\sprintf('The TableCellStyle does not support the following options: \'%s\'.', \implode('\', \'', $diff))); + } + if (isset($options['align']) && !\array_key_exists($options['align'], $this->alignMap)) { + throw new InvalidArgumentException(\sprintf('Wrong align value. Value must be following: \'%s\'.', \implode('\', \'', \array_keys($this->alignMap)))); + } + $this->options = \array_merge($this->options, $options); + } + public function getOptions() + { + $phabelReturn = $this->options; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Gets options we need for tag for example fg, bg. + * + * @return string[] + */ + public function getTagOptions() + { + return \array_filter($this->getOptions(), function ($key) { + return \in_array($key, $this->tagOptions) && isset($this->options[$key]); + }, \ARRAY_FILTER_USE_KEY); + } + public function getPadByAlign() + { + return $this->alignMap[$this->getOptions()['align']]; + } + public function getCellFormat() + { + $phabelReturn = $this->getOptions()['cellFormat']; + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Helper/TableRows.php b/vendor-bundle/symfony/console/Helper/TableRows.php new file mode 100644 index 000000000..b57f99bed --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/TableRows.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +/** + * @internal + */ +class TableRows implements \IteratorAggregate +{ + private $generator; + public function __construct(callable $generator) + { + $this->generator = $generator; + } + public function getIterator() + { + $g = $this->generator; + $phabelReturn = $g(); + if (!$phabelReturn instanceof \Traversable) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Traversable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Helper/TableSeparator.php b/vendor-bundle/symfony/console/Helper/TableSeparator.php new file mode 100644 index 000000000..80db0f9a1 --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/TableSeparator.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +/** + * Marks a row as being a separator. + * + * @author Fabien Potencier + */ +class TableSeparator extends TableCell +{ + public function __construct($options = []) + { + if (!\is_array($options)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($options) must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($options) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + parent::__construct('', $options); + } +} diff --git a/vendor-bundle/symfony/console/Helper/TableStyle.php b/vendor-bundle/symfony/console/Helper/TableStyle.php new file mode 100644 index 000000000..7a6024086 --- /dev/null +++ b/vendor-bundle/symfony/console/Helper/TableStyle.php @@ -0,0 +1,541 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Helper; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Exception\LogicException; +/** + * Defines the styles for a Table. + * + * @author Fabien Potencier + * @author Саша Стаменковић + * @author Dany Maillard + */ +class TableStyle +{ + private $paddingChar = ' '; + private $horizontalOutsideBorderChar = '-'; + private $horizontalInsideBorderChar = '-'; + private $verticalOutsideBorderChar = '|'; + private $verticalInsideBorderChar = '|'; + private $crossingChar = '+'; + private $crossingTopRightChar = '+'; + private $crossingTopMidChar = '+'; + private $crossingTopLeftChar = '+'; + private $crossingMidRightChar = '+'; + private $crossingBottomRightChar = '+'; + private $crossingBottomMidChar = '+'; + private $crossingBottomLeftChar = '+'; + private $crossingMidLeftChar = '+'; + private $crossingTopLeftBottomChar = '+'; + private $crossingTopMidBottomChar = '+'; + private $crossingTopRightBottomChar = '+'; + private $headerTitleFormat = ' %s '; + private $footerTitleFormat = ' %s '; + private $cellHeaderFormat = '%s'; + private $cellRowFormat = '%s'; + private $cellRowContentFormat = ' %s '; + private $borderFormat = '%s'; + private $padType = \STR_PAD_RIGHT; + /** + * Sets padding character, used for cell padding. + * + * @return $this + */ + public function setPaddingChar($paddingChar) + { + if (!\is_string($paddingChar)) { + if (!(\is_string($paddingChar) || \is_object($paddingChar) && \method_exists($paddingChar, '__toString') || (\is_bool($paddingChar) || \is_numeric($paddingChar)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($paddingChar) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($paddingChar) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $paddingChar = (string) $paddingChar; + } + } + if (!$paddingChar) { + throw new LogicException('The padding char must not be empty.'); + } + $this->paddingChar = $paddingChar; + return $this; + } + /** + * Gets padding character, used for cell padding. + * + * @return string + */ + public function getPaddingChar() + { + return $this->paddingChar; + } + /** + * Sets horizontal border characters. + * + * + * ╔═══════════════╤══════════════════════════╤══════════════════╗ + * 1 ISBN 2 Title │ Author ║ + * ╠═══════════════╪══════════════════════════╪══════════════════╣ + * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ + * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ + * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ + * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ + * ╚═══════════════╧══════════════════════════╧══════════════════╝ + * + */ + public function setHorizontalBorderChars($outside, $inside = null) + { + if (!\is_string($outside)) { + if (!(\is_string($outside) || \is_object($outside) && \method_exists($outside, '__toString') || (\is_bool($outside) || \is_numeric($outside)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($outside) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($outside) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $outside = (string) $outside; + } + } + if (!\is_null($inside)) { + if (!\is_string($inside)) { + if (!(\is_string($inside) || \is_object($inside) && \method_exists($inside, '__toString') || (\is_bool($inside) || \is_numeric($inside)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($inside) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($inside) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $inside = (string) $inside; + } + } + } + $this->horizontalOutsideBorderChar = $outside; + $this->horizontalInsideBorderChar = isset($inside) ? $inside : $outside; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Sets vertical border characters. + * + * + * ╔═══════════════╤══════════════════════════╤══════════════════╗ + * ║ ISBN │ Title │ Author ║ + * ╠═══════1═══════╪══════════════════════════╪══════════════════╣ + * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ + * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ + * ╟───────2───────┼──────────────────────────┼──────────────────╢ + * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ + * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ + * ╚═══════════════╧══════════════════════════╧══════════════════╝ + * + */ + public function setVerticalBorderChars($outside, $inside = null) + { + if (!\is_string($outside)) { + if (!(\is_string($outside) || \is_object($outside) && \method_exists($outside, '__toString') || (\is_bool($outside) || \is_numeric($outside)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($outside) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($outside) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $outside = (string) $outside; + } + } + if (!\is_null($inside)) { + if (!\is_string($inside)) { + if (!(\is_string($inside) || \is_object($inside) && \method_exists($inside, '__toString') || (\is_bool($inside) || \is_numeric($inside)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($inside) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($inside) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $inside = (string) $inside; + } + } + } + $this->verticalOutsideBorderChar = $outside; + $this->verticalInsideBorderChar = isset($inside) ? $inside : $outside; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Gets border characters. + * + * @internal + */ + public function getBorderChars() + { + $phabelReturn = [$this->horizontalOutsideBorderChar, $this->verticalOutsideBorderChar, $this->horizontalInsideBorderChar, $this->verticalInsideBorderChar]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Sets crossing characters. + * + * Example: + * + * 1═══════════════2══════════════════════════2══════════════════3 + * ║ ISBN │ Title │ Author ║ + * 8'══════════════0'═════════════════════════0'═════════════════4' + * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ + * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ + * 8───────────────0──────────────────────────0──────────────────4 + * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ + * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ + * 7═══════════════6══════════════════════════6══════════════════5 + * + * + * @param string $cross Crossing char (see #0 of example) + * @param string $topLeft Top left char (see #1 of example) + * @param string $topMid Top mid char (see #2 of example) + * @param string $topRight Top right char (see #3 of example) + * @param string $midRight Mid right char (see #4 of example) + * @param string $bottomRight Bottom right char (see #5 of example) + * @param string $bottomMid Bottom mid char (see #6 of example) + * @param string $bottomLeft Bottom left char (see #7 of example) + * @param string $midLeft Mid left char (see #8 of example) + * @param string|null $topLeftBottom Top left bottom char (see #8' of example), equals to $midLeft if null + * @param string|null $topMidBottom Top mid bottom char (see #0' of example), equals to $cross if null + * @param string|null $topRightBottom Top right bottom char (see #4' of example), equals to $midRight if null + */ + public function setCrossingChars($cross, $topLeft, $topMid, $topRight, $midRight, $bottomRight, $bottomMid, $bottomLeft, $midLeft, $topLeftBottom = null, $topMidBottom = null, $topRightBottom = null) + { + if (!\is_string($cross)) { + if (!(\is_string($cross) || \is_object($cross) && \method_exists($cross, '__toString') || (\is_bool($cross) || \is_numeric($cross)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($cross) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cross) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cross = (string) $cross; + } + } + if (!\is_string($topLeft)) { + if (!(\is_string($topLeft) || \is_object($topLeft) && \method_exists($topLeft, '__toString') || (\is_bool($topLeft) || \is_numeric($topLeft)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($topLeft) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($topLeft) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $topLeft = (string) $topLeft; + } + } + if (!\is_string($topMid)) { + if (!(\is_string($topMid) || \is_object($topMid) && \method_exists($topMid, '__toString') || (\is_bool($topMid) || \is_numeric($topMid)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($topMid) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($topMid) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $topMid = (string) $topMid; + } + } + if (!\is_string($topRight)) { + if (!(\is_string($topRight) || \is_object($topRight) && \method_exists($topRight, '__toString') || (\is_bool($topRight) || \is_numeric($topRight)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($topRight) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($topRight) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $topRight = (string) $topRight; + } + } + if (!\is_string($midRight)) { + if (!(\is_string($midRight) || \is_object($midRight) && \method_exists($midRight, '__toString') || (\is_bool($midRight) || \is_numeric($midRight)))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($midRight) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($midRight) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $midRight = (string) $midRight; + } + } + if (!\is_string($bottomRight)) { + if (!(\is_string($bottomRight) || \is_object($bottomRight) && \method_exists($bottomRight, '__toString') || (\is_bool($bottomRight) || \is_numeric($bottomRight)))) { + throw new \TypeError(__METHOD__ . '(): Argument #6 ($bottomRight) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($bottomRight) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $bottomRight = (string) $bottomRight; + } + } + if (!\is_string($bottomMid)) { + if (!(\is_string($bottomMid) || \is_object($bottomMid) && \method_exists($bottomMid, '__toString') || (\is_bool($bottomMid) || \is_numeric($bottomMid)))) { + throw new \TypeError(__METHOD__ . '(): Argument #7 ($bottomMid) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($bottomMid) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $bottomMid = (string) $bottomMid; + } + } + if (!\is_string($bottomLeft)) { + if (!(\is_string($bottomLeft) || \is_object($bottomLeft) && \method_exists($bottomLeft, '__toString') || (\is_bool($bottomLeft) || \is_numeric($bottomLeft)))) { + throw new \TypeError(__METHOD__ . '(): Argument #8 ($bottomLeft) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($bottomLeft) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $bottomLeft = (string) $bottomLeft; + } + } + if (!\is_string($midLeft)) { + if (!(\is_string($midLeft) || \is_object($midLeft) && \method_exists($midLeft, '__toString') || (\is_bool($midLeft) || \is_numeric($midLeft)))) { + throw new \TypeError(__METHOD__ . '(): Argument #9 ($midLeft) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($midLeft) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $midLeft = (string) $midLeft; + } + } + if (!\is_null($topLeftBottom)) { + if (!\is_string($topLeftBottom)) { + if (!(\is_string($topLeftBottom) || \is_object($topLeftBottom) && \method_exists($topLeftBottom, '__toString') || (\is_bool($topLeftBottom) || \is_numeric($topLeftBottom)))) { + throw new \TypeError(__METHOD__ . '(): Argument #10 ($topLeftBottom) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($topLeftBottom) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $topLeftBottom = (string) $topLeftBottom; + } + } + } + if (!\is_null($topMidBottom)) { + if (!\is_string($topMidBottom)) { + if (!(\is_string($topMidBottom) || \is_object($topMidBottom) && \method_exists($topMidBottom, '__toString') || (\is_bool($topMidBottom) || \is_numeric($topMidBottom)))) { + throw new \TypeError(__METHOD__ . '(): Argument #11 ($topMidBottom) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($topMidBottom) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $topMidBottom = (string) $topMidBottom; + } + } + } + if (!\is_null($topRightBottom)) { + if (!\is_string($topRightBottom)) { + if (!(\is_string($topRightBottom) || \is_object($topRightBottom) && \method_exists($topRightBottom, '__toString') || (\is_bool($topRightBottom) || \is_numeric($topRightBottom)))) { + throw new \TypeError(__METHOD__ . '(): Argument #12 ($topRightBottom) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($topRightBottom) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $topRightBottom = (string) $topRightBottom; + } + } + } + $this->crossingChar = $cross; + $this->crossingTopLeftChar = $topLeft; + $this->crossingTopMidChar = $topMid; + $this->crossingTopRightChar = $topRight; + $this->crossingMidRightChar = $midRight; + $this->crossingBottomRightChar = $bottomRight; + $this->crossingBottomMidChar = $bottomMid; + $this->crossingBottomLeftChar = $bottomLeft; + $this->crossingMidLeftChar = $midLeft; + $this->crossingTopLeftBottomChar = isset($topLeftBottom) ? $topLeftBottom : $midLeft; + $this->crossingTopMidBottomChar = isset($topMidBottom) ? $topMidBottom : $cross; + $this->crossingTopRightBottomChar = isset($topRightBottom) ? $topRightBottom : $midRight; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Sets default crossing character used for each cross. + * + * @see {@link setCrossingChars()} for setting each crossing individually. + */ + public function setDefaultCrossingChar($char) + { + if (!\is_string($char)) { + if (!(\is_string($char) || \is_object($char) && \method_exists($char, '__toString') || (\is_bool($char) || \is_numeric($char)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($char) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($char) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $char = (string) $char; + } + } + $phabelReturn = $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char); + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Gets crossing character. + * + * @return string + */ + public function getCrossingChar() + { + return $this->crossingChar; + } + /** + * Gets crossing characters. + * + * @internal + */ + public function getCrossingChars() + { + $phabelReturn = [$this->crossingChar, $this->crossingTopLeftChar, $this->crossingTopMidChar, $this->crossingTopRightChar, $this->crossingMidRightChar, $this->crossingBottomRightChar, $this->crossingBottomMidChar, $this->crossingBottomLeftChar, $this->crossingMidLeftChar, $this->crossingTopLeftBottomChar, $this->crossingTopMidBottomChar, $this->crossingTopRightBottomChar]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Sets header cell format. + * + * @return $this + */ + public function setCellHeaderFormat($cellHeaderFormat) + { + if (!\is_string($cellHeaderFormat)) { + if (!(\is_string($cellHeaderFormat) || \is_object($cellHeaderFormat) && \method_exists($cellHeaderFormat, '__toString') || (\is_bool($cellHeaderFormat) || \is_numeric($cellHeaderFormat)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($cellHeaderFormat) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cellHeaderFormat) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cellHeaderFormat = (string) $cellHeaderFormat; + } + } + $this->cellHeaderFormat = $cellHeaderFormat; + return $this; + } + /** + * Gets header cell format. + * + * @return string + */ + public function getCellHeaderFormat() + { + return $this->cellHeaderFormat; + } + /** + * Sets row cell format. + * + * @return $this + */ + public function setCellRowFormat($cellRowFormat) + { + if (!\is_string($cellRowFormat)) { + if (!(\is_string($cellRowFormat) || \is_object($cellRowFormat) && \method_exists($cellRowFormat, '__toString') || (\is_bool($cellRowFormat) || \is_numeric($cellRowFormat)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($cellRowFormat) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cellRowFormat) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cellRowFormat = (string) $cellRowFormat; + } + } + $this->cellRowFormat = $cellRowFormat; + return $this; + } + /** + * Gets row cell format. + * + * @return string + */ + public function getCellRowFormat() + { + return $this->cellRowFormat; + } + /** + * Sets row cell content format. + * + * @return $this + */ + public function setCellRowContentFormat($cellRowContentFormat) + { + if (!\is_string($cellRowContentFormat)) { + if (!(\is_string($cellRowContentFormat) || \is_object($cellRowContentFormat) && \method_exists($cellRowContentFormat, '__toString') || (\is_bool($cellRowContentFormat) || \is_numeric($cellRowContentFormat)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($cellRowContentFormat) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cellRowContentFormat) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cellRowContentFormat = (string) $cellRowContentFormat; + } + } + $this->cellRowContentFormat = $cellRowContentFormat; + return $this; + } + /** + * Gets row cell content format. + * + * @return string + */ + public function getCellRowContentFormat() + { + return $this->cellRowContentFormat; + } + /** + * Sets table border format. + * + * @return $this + */ + public function setBorderFormat($borderFormat) + { + if (!\is_string($borderFormat)) { + if (!(\is_string($borderFormat) || \is_object($borderFormat) && \method_exists($borderFormat, '__toString') || (\is_bool($borderFormat) || \is_numeric($borderFormat)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($borderFormat) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($borderFormat) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $borderFormat = (string) $borderFormat; + } + } + $this->borderFormat = $borderFormat; + return $this; + } + /** + * Gets table border format. + * + * @return string + */ + public function getBorderFormat() + { + return $this->borderFormat; + } + /** + * Sets cell padding type. + * + * @return $this + */ + public function setPadType($padType) + { + if (!\is_int($padType)) { + if (!(\is_bool($padType) || \is_numeric($padType))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($padType) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($padType) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $padType = (int) $padType; + } + } + if (!\in_array($padType, [\STR_PAD_LEFT, \STR_PAD_RIGHT, \STR_PAD_BOTH], \true)) { + throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).'); + } + $this->padType = $padType; + return $this; + } + /** + * Gets cell padding type. + * + * @return int + */ + public function getPadType() + { + return $this->padType; + } + public function getHeaderTitleFormat() + { + $phabelReturn = $this->headerTitleFormat; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function setHeaderTitleFormat($format) + { + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $format = (string) $format; + } + } + $this->headerTitleFormat = $format; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getFooterTitleFormat() + { + $phabelReturn = $this->footerTitleFormat; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function setFooterTitleFormat($format) + { + if (!\is_string($format)) { + if (!(\is_string($format) || \is_object($format) && \method_exists($format, '__toString') || (\is_bool($format) || \is_numeric($format)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($format) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($format) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $format = (string) $format; + } + } + $this->footerTitleFormat = $format; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Input/ArgvInput.php b/vendor-bundle/symfony/console/Input/ArgvInput.php new file mode 100644 index 000000000..184001ffb --- /dev/null +++ b/vendor-bundle/symfony/console/Input/ArgvInput.php @@ -0,0 +1,378 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Input; + +use Phabel\Symfony\Component\Console\Exception\RuntimeException; +/** + * ArgvInput represents an input coming from the CLI arguments. + * + * Usage: + * + * $input = new ArgvInput(); + * + * By default, the `$_SERVER['argv']` array is used for the input values. + * + * This can be overridden by explicitly passing the input values in the constructor: + * + * $input = new ArgvInput($_SERVER['argv']); + * + * If you pass it yourself, don't forget that the first element of the array + * is the name of the running application. + * + * When passing an argument to the constructor, be sure that it respects + * the same rules as the argv one. It's almost always better to use the + * `StringInput` when you want to provide your own input. + * + * @author Fabien Potencier + * + * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html + * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02 + */ +class ArgvInput extends Input +{ + private $tokens; + private $parsed; + public function __construct(array $argv = null, InputDefinition $definition = null) + { + $argv = isset($argv) ? $argv : (isset($_SERVER['argv']) ? $_SERVER['argv'] : []); + // strip the application name + \array_shift($argv); + $this->tokens = $argv; + parent::__construct($definition); + } + protected function setTokens(array $tokens) + { + $this->tokens = $tokens; + } + /** + * {@inheritdoc} + */ + protected function parse() + { + $parseOptions = \true; + $this->parsed = $this->tokens; + while (null !== ($token = \array_shift($this->parsed))) { + if ($parseOptions && '' == $token) { + $this->parseArgument($token); + } elseif ($parseOptions && '--' == $token) { + $parseOptions = \false; + } elseif ($parseOptions && \str_starts_with($token, '--')) { + $this->parseLongOption($token); + } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) { + $this->parseShortOption($token); + } else { + $this->parseArgument($token); + } + } + } + /** + * Parses a short option. + */ + private function parseShortOption($token) + { + if (!\is_string($token)) { + if (!(\is_string($token) || \is_object($token) && \method_exists($token, '__toString') || (\is_bool($token) || \is_numeric($token)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($token) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($token) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $token = (string) $token; + } + } + $name = \substr($token, 1); + if (\strlen($name) > 1) { + if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) { + // an option with a value (with no space) + $this->addShortOption($name[0], \substr($name, 1)); + } else { + $this->parseShortOptionSet($name); + } + } else { + $this->addShortOption($name, null); + } + } + /** + * Parses a short option set. + * + * @throws RuntimeException When option given doesn't exist + */ + private function parseShortOptionSet($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $len = \strlen($name); + for ($i = 0; $i < $len; ++$i) { + if (!$this->definition->hasShortcut($name[$i])) { + $encoding = \mb_detect_encoding($name, null, \true); + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', \false === $encoding ? $name[$i] : \mb_substr($name, $i, 1, $encoding))); + } + $option = $this->definition->getOptionForShortcut($name[$i]); + if ($option->acceptValue()) { + $this->addLongOption($option->getName(), $i === $len - 1 ? null : \substr($name, $i + 1)); + break; + } else { + $this->addLongOption($option->getName(), null); + } + } + } + /** + * Parses a long option. + */ + private function parseLongOption($token) + { + if (!\is_string($token)) { + if (!(\is_string($token) || \is_object($token) && \method_exists($token, '__toString') || (\is_bool($token) || \is_numeric($token)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($token) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($token) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $token = (string) $token; + } + } + $name = \substr($token, 2); + if (\false !== ($pos = \strpos($name, '='))) { + if (0 === \strlen($value = \substr($name, $pos + 1))) { + \array_unshift($this->parsed, $value); + } + $this->addLongOption(\substr($name, 0, $pos), $value); + } else { + $this->addLongOption($name, null); + } + } + /** + * Parses an argument. + * + * @throws RuntimeException When too many arguments are given + */ + private function parseArgument($token) + { + if (!\is_string($token)) { + if (!(\is_string($token) || \is_object($token) && \method_exists($token, '__toString') || (\is_bool($token) || \is_numeric($token)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($token) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($token) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $token = (string) $token; + } + } + $c = \count($this->arguments); + // if input is expecting another argument, add it + if ($this->definition->hasArgument($c)) { + $arg = $this->definition->getArgument($c); + $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token; + // if last argument isArray(), append token to last argument + } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) { + $arg = $this->definition->getArgument($c - 1); + $this->arguments[$arg->getName()][] = $token; + // unexpected argument + } else { + $all = $this->definition->getArguments(); + $symfonyCommandName = null; + if (($inputArgument = isset($all[$key = \array_key_first($all)]) ? $all[$key = \array_key_first($all)] : null) && 'command' === $inputArgument->getName()) { + $symfonyCommandName = isset($this->arguments['command']) ? $this->arguments['command'] : null; + unset($all[$key]); + } + if (\count($all)) { + if ($symfonyCommandName) { + $message = \sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, \implode('" "', \array_keys($all))); + } else { + $message = \sprintf('Too many arguments, expected arguments "%s".', \implode('" "', \array_keys($all))); + } + } elseif ($symfonyCommandName) { + $message = \sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); + } else { + $message = \sprintf('No arguments expected, got "%s".', $token); + } + throw new RuntimeException($message); + } + } + /** + * Adds a short option value. + * + * @throws RuntimeException When option given doesn't exist + */ + private function addShortOption($shortcut, $value) + { + if (!\is_string($shortcut)) { + if (!(\is_string($shortcut) || \is_object($shortcut) && \method_exists($shortcut, '__toString') || (\is_bool($shortcut) || \is_numeric($shortcut)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($shortcut) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($shortcut) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $shortcut = (string) $shortcut; + } + } + if (!$this->definition->hasShortcut($shortcut)) { + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', $shortcut)); + } + $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); + } + /** + * Adds a long option value. + * + * @throws RuntimeException When option given doesn't exist + */ + private function addLongOption($name, $value) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!$this->definition->hasOption($name)) { + if (!$this->definition->hasNegation($name)) { + throw new RuntimeException(\sprintf('The "--%s" option does not exist.', $name)); + } + $optionName = $this->definition->negationToName($name); + if (null !== $value) { + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); + } + $this->options[$optionName] = \false; + return; + } + $option = $this->definition->getOption($name); + if (null !== $value && !$option->acceptValue()) { + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); + } + if (\in_array($value, ['', null], \true) && $option->acceptValue() && \count($this->parsed)) { + // if option accepts an optional or mandatory argument + // let's see if there is one provided + $next = \array_shift($this->parsed); + if (isset($next[0]) && '-' !== $next[0] || \in_array($next, ['', null], \true)) { + $value = $next; + } else { + \array_unshift($this->parsed, $next); + } + } + if (null === $value) { + if ($option->isValueRequired()) { + throw new RuntimeException(\sprintf('The "--%s" option requires a value.', $name)); + } + if (!$option->isArray() && !$option->isValueOptional()) { + $value = \true; + } + } + if ($option->isArray()) { + $this->options[$name][] = $value; + } else { + $this->options[$name] = $value; + } + } + /** + * {@inheritdoc} + */ + public function getFirstArgument() + { + $isOption = \false; + foreach ($this->tokens as $i => $token) { + if ($token && '-' === $token[0]) { + if (\str_contains($token, '=') || !isset($this->tokens[$i + 1])) { + continue; + } + // If it's a long option, consider that everything after "--" is the option name. + // Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator) + $name = '-' === $token[1] ? \substr($token, 2) : \substr($token, -1); + if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) { + // noop + } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) { + $isOption = \true; + } + continue; + } + if ($isOption) { + $isOption = \false; + continue; + } + return $token; + } + return null; + } + /** + * {@inheritdoc} + */ + public function hasParameterOption($values, $onlyParams = \false) + { + if (!\is_bool($onlyParams)) { + if (!(\is_bool($onlyParams) || \is_numeric($onlyParams) || \is_string($onlyParams))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($onlyParams) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($onlyParams) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $onlyParams = (bool) $onlyParams; + } + } + $values = (array) $values; + foreach ($this->tokens as $token) { + if ($onlyParams && '--' === $token) { + return \false; + } + foreach ($values as $value) { + // Options with values: + // For long options, test for '--option=' at beginning + // For short options, test for '-o' at beginning + $leading = \str_starts_with($value, '--') ? $value . '=' : $value; + if ($token === $value || '' !== $leading && \str_starts_with($token, $leading)) { + return \true; + } + } + } + return \false; + } + /** + * {@inheritdoc} + */ + public function getParameterOption($values, $default = \false, $onlyParams = \false) + { + if (!\is_bool($onlyParams)) { + if (!(\is_bool($onlyParams) || \is_numeric($onlyParams) || \is_string($onlyParams))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($onlyParams) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($onlyParams) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $onlyParams = (bool) $onlyParams; + } + } + $values = (array) $values; + $tokens = $this->tokens; + while (0 < \count($tokens)) { + $token = \array_shift($tokens); + if ($onlyParams && '--' === $token) { + return $default; + } + foreach ($values as $value) { + if ($token === $value) { + return \array_shift($tokens); + } + // Options with values: + // For long options, test for '--option=' at beginning + // For short options, test for '-o' at beginning + $leading = \str_starts_with($value, '--') ? $value . '=' : $value; + if ('' !== $leading && \str_starts_with($token, $leading)) { + return \substr($token, \strlen($leading)); + } + } + } + return $default; + } + /** + * Returns a stringified representation of the args passed to the command. + * + * @return string + */ + public function __toString() + { + $tokens = \array_map(function ($token) { + if (\preg_match('{^(-[^=]+=)(.+)}', $token, $match)) { + return $match[1] . $this->escapeToken($match[2]); + } + if ($token && '-' !== $token[0]) { + return $this->escapeToken($token); + } + return $token; + }, $this->tokens); + return \implode(' ', $tokens); + } +} diff --git a/vendor-bundle/symfony/console/Input/ArrayInput.php b/vendor-bundle/symfony/console/Input/ArrayInput.php new file mode 100644 index 000000000..717ba0e4d --- /dev/null +++ b/vendor-bundle/symfony/console/Input/ArrayInput.php @@ -0,0 +1,208 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Input; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Exception\InvalidOptionException; +/** + * ArrayInput represents an input provided as an array. + * + * Usage: + * + * $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']); + * + * @author Fabien Potencier + */ +class ArrayInput extends Input +{ + private $parameters; + public function __construct(array $parameters, InputDefinition $definition = null) + { + $this->parameters = $parameters; + parent::__construct($definition); + } + /** + * {@inheritdoc} + */ + public function getFirstArgument() + { + foreach ($this->parameters as $param => $value) { + if ($param && \is_string($param) && '-' === $param[0]) { + continue; + } + return $value; + } + return null; + } + /** + * {@inheritdoc} + */ + public function hasParameterOption($values, $onlyParams = \false) + { + if (!\is_bool($onlyParams)) { + if (!(\is_bool($onlyParams) || \is_numeric($onlyParams) || \is_string($onlyParams))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($onlyParams) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($onlyParams) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $onlyParams = (bool) $onlyParams; + } + } + $values = (array) $values; + foreach ($this->parameters as $k => $v) { + if (!\is_int($k)) { + $v = $k; + } + if ($onlyParams && '--' === $v) { + return \false; + } + if (\in_array($v, $values)) { + return \true; + } + } + return \false; + } + /** + * {@inheritdoc} + */ + public function getParameterOption($values, $default = \false, $onlyParams = \false) + { + if (!\is_bool($onlyParams)) { + if (!(\is_bool($onlyParams) || \is_numeric($onlyParams) || \is_string($onlyParams))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($onlyParams) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($onlyParams) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $onlyParams = (bool) $onlyParams; + } + } + $values = (array) $values; + foreach ($this->parameters as $k => $v) { + if ($onlyParams && ('--' === $k || \is_int($k) && '--' === $v)) { + return $default; + } + if (\is_int($k)) { + if (\in_array($v, $values)) { + return \true; + } + } elseif (\in_array($k, $values)) { + return $v; + } + } + return $default; + } + /** + * Returns a stringified representation of the args passed to the command. + * + * @return string + */ + public function __toString() + { + $params = []; + foreach ($this->parameters as $param => $val) { + if ($param && \is_string($param) && '-' === $param[0]) { + $glue = '-' === $param[1] ? '=' : ' '; + if (\is_array($val)) { + foreach ($val as $v) { + $params[] = $param . ('' != $v ? $glue . $this->escapeToken($v) : ''); + } + } else { + $params[] = $param . ('' != $val ? $glue . $this->escapeToken($val) : ''); + } + } else { + $params[] = \is_array($val) ? \implode(' ', \array_map([$this, 'escapeToken'], $val)) : $this->escapeToken($val); + } + } + return \implode(' ', $params); + } + /** + * {@inheritdoc} + */ + protected function parse() + { + foreach ($this->parameters as $key => $value) { + if ('--' === $key) { + return; + } + if (\str_starts_with($key, '--')) { + $this->addLongOption(\substr($key, 2), $value); + } elseif (\str_starts_with($key, '-')) { + $this->addShortOption(\substr($key, 1), $value); + } else { + $this->addArgument($key, $value); + } + } + } + /** + * Adds a short option value. + * + * @throws InvalidOptionException When option given doesn't exist + */ + private function addShortOption($shortcut, $value) + { + if (!\is_string($shortcut)) { + if (!(\is_string($shortcut) || \is_object($shortcut) && \method_exists($shortcut, '__toString') || (\is_bool($shortcut) || \is_numeric($shortcut)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($shortcut) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($shortcut) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $shortcut = (string) $shortcut; + } + } + if (!$this->definition->hasShortcut($shortcut)) { + throw new InvalidOptionException(\sprintf('The "-%s" option does not exist.', $shortcut)); + } + $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); + } + /** + * Adds a long option value. + * + * @throws InvalidOptionException When option given doesn't exist + * @throws InvalidOptionException When a required value is missing + */ + private function addLongOption($name, $value) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!$this->definition->hasOption($name)) { + if (!$this->definition->hasNegation($name)) { + throw new InvalidOptionException(\sprintf('The "--%s" option does not exist.', $name)); + } + $optionName = $this->definition->negationToName($name); + $this->options[$optionName] = \false; + return; + } + $option = $this->definition->getOption($name); + if (null === $value) { + if ($option->isValueRequired()) { + throw new InvalidOptionException(\sprintf('The "--%s" option requires a value.', $name)); + } + if (!$option->isValueOptional()) { + $value = \true; + } + } + $this->options[$name] = $value; + } + /** + * Adds an argument value. + * + * @param string|int $name The argument name + * @param mixed $value The value for the argument + * + * @throws InvalidArgumentException When argument given doesn't exist + */ + private function addArgument($name, $value) + { + if (!$this->definition->hasArgument($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); + } + $this->arguments[$name] = $value; + } +} diff --git a/vendor-bundle/symfony/console/Input/Input.php b/vendor-bundle/symfony/console/Input/Input.php new file mode 100644 index 000000000..79f83c0e6 --- /dev/null +++ b/vendor-bundle/symfony/console/Input/Input.php @@ -0,0 +1,240 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Input; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Exception\RuntimeException; +/** + * Input is the base class for all concrete Input classes. + * + * Three concrete classes are provided by default: + * + * * `ArgvInput`: The input comes from the CLI arguments (argv) + * * `StringInput`: The input is provided as a string + * * `ArrayInput`: The input is provided as an array + * + * @author Fabien Potencier + */ +abstract class Input implements InputInterface, StreamableInputInterface +{ + protected $definition; + protected $stream; + protected $options = []; + protected $arguments = []; + protected $interactive = \true; + public function __construct(InputDefinition $definition = null) + { + if (null === $definition) { + $this->definition = new InputDefinition(); + } else { + $this->bind($definition); + $this->validate(); + } + } + /** + * {@inheritdoc} + */ + public function bind(InputDefinition $definition) + { + $this->arguments = []; + $this->options = []; + $this->definition = $definition; + $this->parse(); + } + /** + * Processes command line arguments. + */ + protected abstract function parse(); + /** + * {@inheritdoc} + */ + public function validate() + { + $definition = $this->definition; + $givenArguments = $this->arguments; + $missingArguments = \array_filter(\array_keys($definition->getArguments()), function ($argument) use($definition, $givenArguments) { + return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired(); + }); + if (\count($missingArguments) > 0) { + throw new RuntimeException(\sprintf('Not enough arguments (missing: "%s").', \implode(', ', $missingArguments))); + } + } + /** + * {@inheritdoc} + */ + public function isInteractive() + { + return $this->interactive; + } + /** + * {@inheritdoc} + */ + public function setInteractive($interactive) + { + if (!\is_bool($interactive)) { + if (!(\is_bool($interactive) || \is_numeric($interactive) || \is_string($interactive))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($interactive) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($interactive) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $interactive = (bool) $interactive; + } + } + $this->interactive = $interactive; + } + /** + * {@inheritdoc} + */ + public function getArguments() + { + return \array_merge($this->definition->getArgumentDefaults(), $this->arguments); + } + /** + * {@inheritdoc} + */ + public function getArgument($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!$this->definition->hasArgument($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); + } + return isset($this->arguments[$name]) ? $this->arguments[$name] : $this->definition->getArgument($name)->getDefault(); + } + /** + * {@inheritdoc} + */ + public function setArgument($name, $value) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!$this->definition->hasArgument($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); + } + $this->arguments[$name] = $value; + } + /** + * {@inheritdoc} + */ + public function hasArgument($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + return $this->definition->hasArgument($name); + } + /** + * {@inheritdoc} + */ + public function getOptions() + { + return \array_merge($this->definition->getOptionDefaults(), $this->options); + } + /** + * {@inheritdoc} + */ + public function getOption($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if ($this->definition->hasNegation($name)) { + if (null === ($value = $this->getOption($this->definition->negationToName($name)))) { + return $value; + } + return !$value; + } + if (!$this->definition->hasOption($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); + } + return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); + } + /** + * {@inheritdoc} + */ + public function setOption($name, $value) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if ($this->definition->hasNegation($name)) { + $this->options[$this->definition->negationToName($name)] = !$value; + return; + } elseif (!$this->definition->hasOption($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); + } + $this->options[$name] = $value; + } + /** + * {@inheritdoc} + */ + public function hasOption($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + return $this->definition->hasOption($name) || $this->definition->hasNegation($name); + } + /** + * Escapes a token through escapeshellarg if it contains unsafe chars. + * + * @return string + */ + public function escapeToken($token) + { + if (!\is_string($token)) { + if (!(\is_string($token) || \is_object($token) && \method_exists($token, '__toString') || (\is_bool($token) || \is_numeric($token)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($token) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($token) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $token = (string) $token; + } + } + return \preg_match('{^[\\w-]+$}', $token) ? $token : \escapeshellarg($token); + } + /** + * {@inheritdoc} + */ + public function setStream($stream) + { + $this->stream = $stream; + } + /** + * {@inheritdoc} + */ + public function getStream() + { + return $this->stream; + } +} diff --git a/vendor-bundle/symfony/console/Input/InputArgument.php b/vendor-bundle/symfony/console/Input/InputArgument.php new file mode 100644 index 000000000..8b30bf109 --- /dev/null +++ b/vendor-bundle/symfony/console/Input/InputArgument.php @@ -0,0 +1,138 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Input; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Exception\LogicException; +/** + * Represents a command line argument. + * + * @author Fabien Potencier + */ +class InputArgument +{ + const REQUIRED = 1; + const OPTIONAL = 2; + const IS_ARRAY = 4; + private $name; + private $mode; + private $default; + private $description; + /** + * @param string $name The argument name + * @param int|null $mode The argument mode: self::REQUIRED or self::OPTIONAL + * @param string $description A description text + * @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only) + * + * @throws InvalidArgumentException When argument mode is not valid + */ + public function __construct($name, $mode = null, $description = '', $default = null) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_null($mode)) { + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($mode) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $mode = (int) $mode; + } + } + } + if (!\is_string($description)) { + if (!(\is_string($description) || \is_object($description) && \method_exists($description, '__toString') || (\is_bool($description) || \is_numeric($description)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($description) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($description) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $description = (string) $description; + } + } + if (null === $mode) { + $mode = self::OPTIONAL; + } elseif ($mode > 7 || $mode < 1) { + throw new InvalidArgumentException(\sprintf('Argument mode "%s" is not valid.', $mode)); + } + $this->name = $name; + $this->mode = $mode; + $this->description = $description; + $this->setDefault($default); + } + /** + * Returns the argument name. + * + * @return string The argument name + */ + public function getName() + { + return $this->name; + } + /** + * Returns true if the argument is required. + * + * @return bool true if parameter mode is self::REQUIRED, false otherwise + */ + public function isRequired() + { + return self::REQUIRED === (self::REQUIRED & $this->mode); + } + /** + * Returns true if the argument can take multiple values. + * + * @return bool true if mode is self::IS_ARRAY, false otherwise + */ + public function isArray() + { + return self::IS_ARRAY === (self::IS_ARRAY & $this->mode); + } + /** + * Sets the default value. + * + * @param string|bool|int|float|array|null $default + * + * @throws LogicException When incorrect default value is given + */ + public function setDefault($default = null) + { + if (self::REQUIRED === $this->mode && null !== $default) { + throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.'); + } + if ($this->isArray()) { + if (null === $default) { + $default = []; + } elseif (!\is_array($default)) { + throw new LogicException('A default value for an array argument must be an array.'); + } + } + $this->default = $default; + } + /** + * Returns the default value. + * + * @return string|bool|int|float|array|null + */ + public function getDefault() + { + return $this->default; + } + /** + * Returns the description text. + * + * @return string The description text + */ + public function getDescription() + { + return $this->description; + } +} diff --git a/vendor-bundle/symfony/console/Input/InputAwareInterface.php b/vendor-bundle/symfony/console/Input/InputAwareInterface.php new file mode 100644 index 000000000..24852f919 --- /dev/null +++ b/vendor-bundle/symfony/console/Input/InputAwareInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Input; + +/** + * InputAwareInterface should be implemented by classes that depends on the + * Console Input. + * + * @author Wouter J + */ +interface InputAwareInterface +{ + /** + * Sets the Console Input. + */ + public function setInput(InputInterface $input); +} diff --git a/vendor-bundle/symfony/console/Input/InputDefinition.php b/vendor-bundle/symfony/console/Input/InputDefinition.php new file mode 100644 index 000000000..99b8cae9f --- /dev/null +++ b/vendor-bundle/symfony/console/Input/InputDefinition.php @@ -0,0 +1,452 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Input; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Exception\LogicException; +/** + * A InputDefinition represents a set of valid command line arguments and options. + * + * Usage: + * + * $definition = new InputDefinition([ + * new InputArgument('name', InputArgument::REQUIRED), + * new InputOption('foo', 'f', InputOption::VALUE_REQUIRED), + * ]); + * + * @author Fabien Potencier + */ +class InputDefinition +{ + private $arguments; + private $requiredCount; + private $lastArrayArgument; + private $lastOptionalArgument; + private $options; + private $negations; + private $shortcuts; + /** + * @param array $definition An array of InputArgument and InputOption instance + */ + public function __construct(array $definition = []) + { + $this->setDefinition($definition); + } + /** + * Sets the definition of the input. + */ + public function setDefinition(array $definition) + { + $arguments = []; + $options = []; + foreach ($definition as $item) { + if ($item instanceof InputOption) { + $options[] = $item; + } else { + $arguments[] = $item; + } + } + $this->setArguments($arguments); + $this->setOptions($options); + } + /** + * Sets the InputArgument objects. + * + * @param InputArgument[] $arguments An array of InputArgument objects + */ + public function setArguments(array $arguments = []) + { + $this->arguments = []; + $this->requiredCount = 0; + $this->lastOptionalArgument = null; + $this->lastArrayArgument = null; + $this->addArguments($arguments); + } + /** + * Adds an array of InputArgument objects. + * + * @param InputArgument[] $arguments An array of InputArgument objects + */ + public function addArguments($arguments = []) + { + if (!(\is_array($arguments) || \is_null($arguments))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($arguments) must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($arguments) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (null !== $arguments) { + foreach ($arguments as $argument) { + $this->addArgument($argument); + } + } + } + /** + * @throws LogicException When incorrect argument is given + */ + public function addArgument(InputArgument $argument) + { + if (isset($this->arguments[$argument->getName()])) { + throw new LogicException(\sprintf('An argument with name "%s" already exists.', $argument->getName())); + } + if (null !== $this->lastArrayArgument) { + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); + } + if ($argument->isRequired() && null !== $this->lastOptionalArgument) { + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); + } + if ($argument->isArray()) { + $this->lastArrayArgument = $argument; + } + if ($argument->isRequired()) { + ++$this->requiredCount; + } else { + $this->lastOptionalArgument = $argument; + } + $this->arguments[$argument->getName()] = $argument; + } + /** + * Returns an InputArgument by name or by position. + * + * @param string|int $name The InputArgument name or position + * + * @return InputArgument An InputArgument object + * + * @throws InvalidArgumentException When argument given doesn't exist + */ + public function getArgument($name) + { + if (!$this->hasArgument($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); + } + $arguments = \is_int($name) ? \array_values($this->arguments) : $this->arguments; + return $arguments[$name]; + } + /** + * Returns true if an InputArgument object exists by name or position. + * + * @param string|int $name The InputArgument name or position + * + * @return bool true if the InputArgument object exists, false otherwise + */ + public function hasArgument($name) + { + $arguments = \is_int($name) ? \array_values($this->arguments) : $this->arguments; + return isset($arguments[$name]); + } + /** + * Gets the array of InputArgument objects. + * + * @return InputArgument[] An array of InputArgument objects + */ + public function getArguments() + { + return $this->arguments; + } + /** + * Returns the number of InputArguments. + * + * @return int The number of InputArguments + */ + public function getArgumentCount() + { + return null !== $this->lastArrayArgument ? \PHP_INT_MAX : \count($this->arguments); + } + /** + * Returns the number of required InputArguments. + * + * @return int The number of required InputArguments + */ + public function getArgumentRequiredCount() + { + return $this->requiredCount; + } + /** + * @return array + */ + public function getArgumentDefaults() + { + $values = []; + foreach ($this->arguments as $argument) { + $values[$argument->getName()] = $argument->getDefault(); + } + return $values; + } + /** + * Sets the InputOption objects. + * + * @param InputOption[] $options An array of InputOption objects + */ + public function setOptions(array $options = []) + { + $this->options = []; + $this->shortcuts = []; + $this->negations = []; + $this->addOptions($options); + } + /** + * Adds an array of InputOption objects. + * + * @param InputOption[] $options An array of InputOption objects + */ + public function addOptions(array $options = []) + { + foreach ($options as $option) { + $this->addOption($option); + } + } + /** + * @throws LogicException When option given already exist + */ + public function addOption(InputOption $option) + { + if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); + } + if (isset($this->negations[$option->getName()])) { + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); + } + if ($option->getShortcut()) { + foreach (\explode('|', $option->getShortcut()) as $shortcut) { + if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) { + throw new LogicException(\sprintf('An option with shortcut "%s" already exists.', $shortcut)); + } + } + } + $this->options[$option->getName()] = $option; + if ($option->getShortcut()) { + foreach (\explode('|', $option->getShortcut()) as $shortcut) { + $this->shortcuts[$shortcut] = $option->getName(); + } + } + if ($option->isNegatable()) { + $negatedName = 'no-' . $option->getName(); + if (isset($this->options[$negatedName])) { + throw new LogicException(\sprintf('An option named "%s" already exists.', $negatedName)); + } + $this->negations[$negatedName] = $option->getName(); + } + } + /** + * Returns an InputOption by name. + * + * @return InputOption A InputOption object + * + * @throws InvalidArgumentException When option given doesn't exist + */ + public function getOption($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!$this->hasOption($name)) { + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $name)); + } + return $this->options[$name]; + } + /** + * Returns true if an InputOption object exists by name. + * + * This method can't be used to check if the user included the option when + * executing the command (use getOption() instead). + * + * @return bool true if the InputOption object exists, false otherwise + */ + public function hasOption($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + return isset($this->options[$name]); + } + /** + * Gets the array of InputOption objects. + * + * @return InputOption[] An array of InputOption objects + */ + public function getOptions() + { + return $this->options; + } + /** + * Returns true if an InputOption object exists by shortcut. + * + * @return bool true if the InputOption object exists, false otherwise + */ + public function hasShortcut($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + return isset($this->shortcuts[$name]); + } + /** + * Returns true if an InputOption object exists by negated name. + */ + public function hasNegation($name) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + $phabelReturn = isset($this->negations[$name]); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets an InputOption by shortcut. + * + * @return InputOption An InputOption object + */ + public function getOptionForShortcut($shortcut) + { + if (!\is_string($shortcut)) { + if (!(\is_string($shortcut) || \is_object($shortcut) && \method_exists($shortcut, '__toString') || (\is_bool($shortcut) || \is_numeric($shortcut)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($shortcut) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($shortcut) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $shortcut = (string) $shortcut; + } + } + return $this->getOption($this->shortcutToName($shortcut)); + } + /** + * @return array + */ + public function getOptionDefaults() + { + $values = []; + foreach ($this->options as $option) { + $values[$option->getName()] = $option->getDefault(); + } + return $values; + } + /** + * Returns the InputOption name given a shortcut. + * + * @throws InvalidArgumentException When option given does not exist + * + * @internal + */ + public function shortcutToName($shortcut) + { + if (!\is_string($shortcut)) { + if (!(\is_string($shortcut) || \is_object($shortcut) && \method_exists($shortcut, '__toString') || (\is_bool($shortcut) || \is_numeric($shortcut)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($shortcut) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($shortcut) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $shortcut = (string) $shortcut; + } + } + if (!isset($this->shortcuts[$shortcut])) { + throw new InvalidArgumentException(\sprintf('The "-%s" option does not exist.', $shortcut)); + } + $phabelReturn = $this->shortcuts[$shortcut]; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Returns the InputOption name given a negation. + * + * @throws InvalidArgumentException When option given does not exist + * + * @internal + */ + public function negationToName($negation) + { + if (!\is_string($negation)) { + if (!(\is_string($negation) || \is_object($negation) && \method_exists($negation, '__toString') || (\is_bool($negation) || \is_numeric($negation)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($negation) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($negation) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $negation = (string) $negation; + } + } + if (!isset($this->negations[$negation])) { + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $negation)); + } + $phabelReturn = $this->negations[$negation]; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Gets the synopsis. + * + * @return string The synopsis + */ + public function getSynopsis($short = \false) + { + if (!\is_bool($short)) { + if (!(\is_bool($short) || \is_numeric($short) || \is_string($short))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($short) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($short) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $short = (bool) $short; + } + } + $elements = []; + if ($short && $this->getOptions()) { + $elements[] = '[options]'; + } elseif (!$short) { + foreach ($this->getOptions() as $option) { + $value = ''; + if ($option->acceptValue()) { + $value = \sprintf(' %s%s%s', $option->isValueOptional() ? '[' : '', \strtoupper($option->getName()), $option->isValueOptional() ? ']' : ''); + } + $shortcut = $option->getShortcut() ? \sprintf('-%s|', $option->getShortcut()) : ''; + $negation = $option->isNegatable() ? \sprintf('|--no-%s', $option->getName()) : ''; + $elements[] = \sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); + } + } + if (\count($elements) && $this->getArguments()) { + $elements[] = '[--]'; + } + $tail = ''; + foreach ($this->getArguments() as $argument) { + $element = '<' . $argument->getName() . '>'; + if ($argument->isArray()) { + $element .= '...'; + } + if (!$argument->isRequired()) { + $element = '[' . $element; + $tail .= ']'; + } + $elements[] = $element; + } + return \implode(' ', $elements) . $tail; + } +} diff --git a/vendor-bundle/symfony/console/Input/InputInterface.php b/vendor-bundle/symfony/console/Input/InputInterface.php new file mode 100644 index 000000000..52030fd57 --- /dev/null +++ b/vendor-bundle/symfony/console/Input/InputInterface.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Input; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Exception\RuntimeException; +/** + * InputInterface is the interface implemented by all input classes. + * + * @author Fabien Potencier + */ +interface InputInterface +{ + /** + * Returns the first argument from the raw parameters (not parsed). + * + * @return string|null The value of the first argument or null otherwise + */ + public function getFirstArgument(); + /** + * Returns true if the raw parameters (not parsed) contain a value. + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * Does not necessarily return the correct result for short options + * when multiple flags are combined in the same option. + * + * @param string|array $values The values to look for in the raw parameters (can be an array) + * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal + * + * @return bool true if the value is contained in the raw parameters + */ + public function hasParameterOption($values, $onlyParams = \false); + /** + * Returns the value of a raw option (not parsed). + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * Does not necessarily return the correct result for short options + * when multiple flags are combined in the same option. + * + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * @param string|bool|int|float|array|null $default The default value to return if no result is found + * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal + * + * @return mixed The option value + */ + public function getParameterOption($values, $default = \false, $onlyParams = \false); + /** + * Binds the current Input instance with the given arguments and options. + * + * @throws RuntimeException + */ + public function bind(InputDefinition $definition); + /** + * Validates the input. + * + * @throws RuntimeException When not enough arguments are given + */ + public function validate(); + /** + * Returns all the given arguments merged with the default values. + * + * @return array + */ + public function getArguments(); + /** + * Returns the argument value for a given argument name. + * + * @return mixed + * + * @throws InvalidArgumentException When argument given doesn't exist + */ + public function getArgument($name); + /** + * Sets an argument value by name. + * + * @param mixed $value The argument value + * + * @throws InvalidArgumentException When argument given doesn't exist + */ + public function setArgument($name, $value); + /** + * Returns true if an InputArgument object exists by name or position. + * + * @return bool true if the InputArgument object exists, false otherwise + */ + public function hasArgument($name); + /** + * Returns all the given options merged with the default values. + * + * @return array + */ + public function getOptions(); + /** + * Returns the option value for a given option name. + * + * @return mixed + * + * @throws InvalidArgumentException When option given doesn't exist + */ + public function getOption($name); + /** + * Sets an option value by name. + * + * @param mixed $value The option value + * + * @throws InvalidArgumentException When option given doesn't exist + */ + public function setOption($name, $value); + /** + * Returns true if an InputOption object exists by name. + * + * @return bool true if the InputOption object exists, false otherwise + */ + public function hasOption($name); + /** + * Is this input means interactive? + * + * @return bool + */ + public function isInteractive(); + /** + * Sets the input interactivity. + */ + public function setInteractive($interactive); +} diff --git a/vendor-bundle/symfony/console/Input/InputOption.php b/vendor-bundle/symfony/console/Input/InputOption.php new file mode 100644 index 000000000..5cfc1b473 --- /dev/null +++ b/vendor-bundle/symfony/console/Input/InputOption.php @@ -0,0 +1,228 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Input; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Exception\LogicException; +/** + * Represents a command line option. + * + * @author Fabien Potencier + */ +class InputOption +{ + /** + * Do not accept input for the option (e.g. --yell). This is the default behavior of options. + */ + const VALUE_NONE = 1; + /** + * A value must be passed when the option is used (e.g. --iterations=5 or -i5). + */ + const VALUE_REQUIRED = 2; + /** + * The option may or may not have a value (e.g. --yell or --yell=loud). + */ + const VALUE_OPTIONAL = 4; + /** + * The option accepts multiple values (e.g. --dir=/foo --dir=/bar). + */ + const VALUE_IS_ARRAY = 8; + /** + * The option may have either positive or negative value (e.g. --ansi or --no-ansi). + */ + const VALUE_NEGATABLE = 16; + private $name; + private $shortcut; + private $mode; + private $default; + private $description; + /** + * @param string $name The option name + * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts + * @param int|null $mode The option mode: One of the VALUE_* constants + * @param string $description A description text + * @param string|bool|int|float|array|null $default The default value (must be null for self::VALUE_NONE) + * + * @throws InvalidArgumentException If option mode is invalid or incompatible + */ + public function __construct($name, $shortcut = null, $mode = null, $description = '', $default = null) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_null($mode)) { + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($mode) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $mode = (int) $mode; + } + } + } + if (!\is_string($description)) { + if (!(\is_string($description) || \is_object($description) && \method_exists($description, '__toString') || (\is_bool($description) || \is_numeric($description)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($description) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($description) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $description = (string) $description; + } + } + if (\str_starts_with($name, '--')) { + $name = \substr($name, 2); + } + if (empty($name)) { + throw new InvalidArgumentException('An option name cannot be empty.'); + } + if (empty($shortcut)) { + $shortcut = null; + } + if (null !== $shortcut) { + if (\is_array($shortcut)) { + $shortcut = \implode('|', $shortcut); + } + $shortcuts = \preg_split('{(\\|)-?}', \ltrim($shortcut, '-')); + $shortcuts = \array_filter($shortcuts); + $shortcut = \implode('|', $shortcuts); + if (empty($shortcut)) { + throw new InvalidArgumentException('An option shortcut cannot be empty.'); + } + } + if (null === $mode) { + $mode = self::VALUE_NONE; + } elseif ($mode >= self::VALUE_NEGATABLE << 1 || $mode < 1) { + throw new InvalidArgumentException(\sprintf('Option mode "%s" is not valid.', $mode)); + } + $this->name = $name; + $this->shortcut = $shortcut; + $this->mode = $mode; + $this->description = $description; + if ($this->isArray() && !$this->acceptValue()) { + throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.'); + } + if ($this->isNegatable() && $this->acceptValue()) { + throw new InvalidArgumentException('Impossible to have an option mode VALUE_NEGATABLE if the option also accepts a value.'); + } + $this->setDefault($default); + } + /** + * Returns the option shortcut. + * + * @return string|null The shortcut + */ + public function getShortcut() + { + return $this->shortcut; + } + /** + * Returns the option name. + * + * @return string The name + */ + public function getName() + { + return $this->name; + } + /** + * Returns true if the option accepts a value. + * + * @return bool true if value mode is not self::VALUE_NONE, false otherwise + */ + public function acceptValue() + { + return $this->isValueRequired() || $this->isValueOptional(); + } + /** + * Returns true if the option requires a value. + * + * @return bool true if value mode is self::VALUE_REQUIRED, false otherwise + */ + public function isValueRequired() + { + return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode); + } + /** + * Returns true if the option takes an optional value. + * + * @return bool true if value mode is self::VALUE_OPTIONAL, false otherwise + */ + public function isValueOptional() + { + return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode); + } + /** + * Returns true if the option can take multiple values. + * + * @return bool true if mode is self::VALUE_IS_ARRAY, false otherwise + */ + public function isArray() + { + return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode); + } + public function isNegatable() + { + $phabelReturn = self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @param string|bool|int|float|array|null $default + */ + public function setDefault($default = null) + { + if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) { + throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.'); + } + if ($this->isArray()) { + if (null === $default) { + $default = []; + } elseif (!\is_array($default)) { + throw new LogicException('A default value for an array option must be an array.'); + } + } + $this->default = $this->acceptValue() || $this->isNegatable() ? $default : \false; + } + /** + * Returns the default value. + * + * @return string|bool|int|float|array|null + */ + public function getDefault() + { + return $this->default; + } + /** + * Returns the description text. + * + * @return string The description text + */ + public function getDescription() + { + return $this->description; + } + /** + * Checks whether the given option equals this one. + * + * @return bool + */ + public function equals(self $option) + { + return $option->getName() === $this->getName() && $option->getShortcut() === $this->getShortcut() && $option->getDefault() === $this->getDefault() && $option->isNegatable() === $this->isNegatable() && $option->isArray() === $this->isArray() && $option->isValueRequired() === $this->isValueRequired() && $option->isValueOptional() === $this->isValueOptional(); + } +} diff --git a/vendor-bundle/symfony/console/Input/StreamableInputInterface.php b/vendor-bundle/symfony/console/Input/StreamableInputInterface.php new file mode 100644 index 000000000..ba6f45f66 --- /dev/null +++ b/vendor-bundle/symfony/console/Input/StreamableInputInterface.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Input; + +/** + * StreamableInputInterface is the interface implemented by all input classes + * that have an input stream. + * + * @author Robin Chalas + */ +interface StreamableInputInterface extends InputInterface +{ + /** + * Sets the input stream to read from when interacting with the user. + * + * This is mainly useful for testing purpose. + * + * @param resource $stream The input stream + */ + public function setStream($stream); + /** + * Returns the input stream. + * + * @return resource|null + */ + public function getStream(); +} diff --git a/vendor-bundle/symfony/console/Input/StringInput.php b/vendor-bundle/symfony/console/Input/StringInput.php new file mode 100644 index 000000000..05a1b4002 --- /dev/null +++ b/vendor-bundle/symfony/console/Input/StringInput.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Input; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * StringInput represents an input provided as a string. + * + * Usage: + * + * $input = new StringInput('foo --bar="foobar"'); + * + * @author Fabien Potencier + */ +class StringInput extends ArgvInput +{ + const REGEX_STRING = '([^\\s]+?)(?:\\s|(?setTokens($this->tokenize($input)); + } + /** + * Tokenizes a string. + * + * @throws InvalidArgumentException When unable to parse input (should never happen) + */ + private function tokenize($input) + { + if (!\is_string($input)) { + if (!(\is_string($input) || \is_object($input) && \method_exists($input, '__toString') || (\is_bool($input) || \is_numeric($input)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($input) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($input) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $input = (string) $input; + } + } + $tokens = []; + $length = \strlen($input); + $cursor = 0; + while ($cursor < $length) { + if (\preg_match('/\\s+/A', $input, $match, 0, $cursor)) { + } elseif (\preg_match('/([^="\'\\s]+?)(=?)(' . self::REGEX_QUOTED_STRING . '+)/A', $input, $match, 0, $cursor)) { + $tokens[] = $match[1] . $match[2] . \stripcslashes(\str_replace(['"\'', '\'"', '\'\'', '""'], '', \substr($match[3], 1, -1))); + } elseif (\preg_match('/' . self::REGEX_QUOTED_STRING . '/A', $input, $match, 0, $cursor)) { + $tokens[] = \stripcslashes(\substr($match[0], 1, -1)); + } elseif (\preg_match('/' . self::REGEX_STRING . '/A', $input, $match, 0, $cursor)) { + $tokens[] = \stripcslashes($match[1]); + } else { + // should never happen + throw new InvalidArgumentException(\sprintf('Unable to parse input near "... %s ...".', \substr($input, $cursor, 10))); + } + $cursor += \strlen($match[0]); + } + $phabelReturn = $tokens; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Logger/ConsoleLogger.php b/vendor-bundle/symfony/console/Logger/ConsoleLogger.php new file mode 100644 index 000000000..8364bfeea --- /dev/null +++ b/vendor-bundle/symfony/console/Logger/ConsoleLogger.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Logger; + +use Phabel\Psr\Log\AbstractLogger; +use Phabel\Psr\Log\InvalidArgumentException; +use Phabel\Psr\Log\LogLevel; +use Phabel\Symfony\Component\Console\Output\ConsoleOutputInterface; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * PSR-3 compliant console logger. + * + * @author Kévin Dunglas + * + * @see https://www.php-fig.org/psr/psr-3/ + */ +class ConsoleLogger extends AbstractLogger +{ + const INFO = 'info'; + const ERROR = 'error'; + private $output; + private $verbosityLevelMap = [LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL, LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL, LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL, LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE, LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE, LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG]; + private $formatLevelMap = [LogLevel::EMERGENCY => self::ERROR, LogLevel::ALERT => self::ERROR, LogLevel::CRITICAL => self::ERROR, LogLevel::ERROR => self::ERROR, LogLevel::WARNING => self::INFO, LogLevel::NOTICE => self::INFO, LogLevel::INFO => self::INFO, LogLevel::DEBUG => self::INFO]; + private $errored = \false; + public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = []) + { + $this->output = $output; + $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap; + $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap; + } + /** + * {@inheritdoc} + * + * @return void + */ + public function log($level, $message, array $context = []) + { + if (!isset($this->verbosityLevelMap[$level])) { + throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $level)); + } + $output = $this->output; + // Write to the error output if necessary and available + if (self::ERROR === $this->formatLevelMap[$level]) { + if ($this->output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + $this->errored = \true; + } + // the if condition check isn't necessary -- it's the same one that $output will do internally anyway. + // We only do it for efficiency here as the message formatting is relatively expensive. + if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { + $output->writeln(\sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); + } + } + /** + * Returns true when any messages have been logged at error levels. + * + * @return bool + */ + public function hasErrored() + { + return $this->errored; + } + /** + * Interpolates context values into the message placeholders. + * + * @author PHP Framework Interoperability Group + */ + private function interpolate($message, array $context) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\str_contains($message, '{')) { + $phabelReturn = $message; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $replacements = []; + foreach ($context as $key => $val) { + if (null === $val || \is_scalar($val) || \is_object($val) && \method_exists($val, '__toString')) { + $replacements["{{$key}}"] = $val; + } elseif ($val instanceof \DateTimeInterface) { + $replacements["{{$key}}"] = $val->format(\DateTime::RFC3339); + } elseif (\is_object($val)) { + $replacements["{{$key}}"] = '[object ' . \get_class($val) . ']'; + } else { + $replacements["{{$key}}"] = '[' . \gettype($val) . ']'; + } + } + $phabelReturn = \strtr($message, $replacements); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Output/BufferedOutput.php b/vendor-bundle/symfony/console/Output/BufferedOutput.php new file mode 100644 index 000000000..f0555fba4 --- /dev/null +++ b/vendor-bundle/symfony/console/Output/BufferedOutput.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Output; + +/** + * @author Jean-François Simon + */ +class BufferedOutput extends Output +{ + private $buffer = ''; + /** + * Empties buffer and returns its content. + * + * @return string + */ + public function fetch() + { + $content = $this->buffer; + $this->buffer = ''; + return $content; + } + /** + * {@inheritdoc} + */ + protected function doWrite($message, $newline) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_bool($newline)) { + if (!(\is_bool($newline) || \is_numeric($newline) || \is_string($newline))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($newline) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $newline = (bool) $newline; + } + } + $this->buffer .= $message; + if ($newline) { + $this->buffer .= \PHP_EOL; + } + } +} diff --git a/vendor-bundle/symfony/console/Output/ConsoleOutput.php b/vendor-bundle/symfony/console/Output/ConsoleOutput.php new file mode 100644 index 000000000..5e98c8182 --- /dev/null +++ b/vendor-bundle/symfony/console/Output/ConsoleOutput.php @@ -0,0 +1,187 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Output; + +use Phabel\Symfony\Component\Console\Formatter\OutputFormatterInterface; +/** + * ConsoleOutput is the default class for all CLI output. It uses STDOUT and STDERR. + * + * This class is a convenient wrapper around `StreamOutput` for both STDOUT and STDERR. + * + * $output = new ConsoleOutput(); + * + * This is equivalent to: + * + * $output = new StreamOutput(fopen('php://stdout', 'w')); + * $stdErr = new StreamOutput(fopen('php://stderr', 'w')); + * + * @author Fabien Potencier + */ +class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface +{ + private $stderr; + private $consoleSectionOutputs = []; + /** + * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) + * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) + * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) + */ + public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, $formatter = null) + { + if (!($formatter instanceof OutputFormatterInterface || \is_null($formatter))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($formatter) must be of type ?OutputFormatterInterface, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($formatter) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_int($verbosity)) { + if (!(\is_bool($verbosity) || \is_numeric($verbosity))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($verbosity) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($verbosity) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $verbosity = (int) $verbosity; + } + } + if (!\is_null($decorated)) { + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($decorated) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + } + parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter); + if (null === $formatter) { + // for BC reasons, stdErr has it own Formatter only when user don't inject a specific formatter. + $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated); + return; + } + $actualDecorated = $this->isDecorated(); + $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter()); + if (null === $decorated) { + $this->setDecorated($actualDecorated && $this->stderr->isDecorated()); + } + } + /** + * Creates a new output section. + */ + public function section() + { + $phabelReturn = new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter()); + if (!$phabelReturn instanceof ConsoleSectionOutput) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ConsoleSectionOutput, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function setDecorated($decorated) + { + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($decorated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + parent::setDecorated($decorated); + $this->stderr->setDecorated($decorated); + } + /** + * {@inheritdoc} + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + parent::setFormatter($formatter); + $this->stderr->setFormatter($formatter); + } + /** + * {@inheritdoc} + */ + public function setVerbosity($level) + { + if (!\is_int($level)) { + if (!(\is_bool($level) || \is_numeric($level))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($level) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($level) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $level = (int) $level; + } + } + parent::setVerbosity($level); + $this->stderr->setVerbosity($level); + } + /** + * {@inheritdoc} + */ + public function getErrorOutput() + { + return $this->stderr; + } + /** + * {@inheritdoc} + */ + public function setErrorOutput(OutputInterface $error) + { + $this->stderr = $error; + } + /** + * Returns true if current environment supports writing console output to + * STDOUT. + * + * @return bool + */ + protected function hasStdoutSupport() + { + return \false === $this->isRunningOS400(); + } + /** + * Returns true if current environment supports writing console output to + * STDERR. + * + * @return bool + */ + protected function hasStderrSupport() + { + return \false === $this->isRunningOS400(); + } + /** + * Checks if current executing environment is IBM iSeries (OS400), which + * doesn't properly convert character-encodings between ASCII to EBCDIC. + */ + private function isRunningOS400() + { + $checks = [\function_exists('php_uname') ? \php_uname('s') : '', \getenv('OSTYPE'), \PHP_OS]; + $phabelReturn = \false !== \stripos(\implode(';', $checks), 'OS400'); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return resource + */ + private function openOutputStream() + { + if (!$this->hasStdoutSupport()) { + return \fopen('php://output', 'w'); + } + return @\fopen('php://stdout', 'w') ?: \fopen('php://output', 'w'); + } + /** + * @return resource + */ + private function openErrorStream() + { + return \fopen($this->hasStderrSupport() ? 'php://stderr' : 'php://output', 'w'); + } +} diff --git a/vendor-bundle/symfony/console/Output/ConsoleOutputInterface.php b/vendor-bundle/symfony/console/Output/ConsoleOutputInterface.php new file mode 100644 index 000000000..f6d3f9be6 --- /dev/null +++ b/vendor-bundle/symfony/console/Output/ConsoleOutputInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Output; + +/** + * ConsoleOutputInterface is the interface implemented by ConsoleOutput class. + * This adds information about stderr and section output stream. + * + * @author Dariusz Górecki + */ +interface ConsoleOutputInterface extends OutputInterface +{ + /** + * Gets the OutputInterface for errors. + * + * @return OutputInterface + */ + public function getErrorOutput(); + public function setErrorOutput(OutputInterface $error); + public function section(); +} diff --git a/vendor-bundle/symfony/console/Output/ConsoleSectionOutput.php b/vendor-bundle/symfony/console/Output/ConsoleSectionOutput.php new file mode 100644 index 000000000..444f04583 --- /dev/null +++ b/vendor-bundle/symfony/console/Output/ConsoleSectionOutput.php @@ -0,0 +1,208 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Output; + +use Phabel\Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Phabel\Symfony\Component\Console\Helper\Helper; +use Phabel\Symfony\Component\Console\Terminal; +/** + * @author Pierre du Plessis + * @author Gabriel Ostrolucký + */ +class ConsoleSectionOutput extends StreamOutput +{ + private $content = []; + private $lines = 0; + private $sections; + private $terminal; + /** + * @param resource $stream + * @param ConsoleSectionOutput[] $sections + */ + public function __construct($stream, &$sections, $verbosity, $decorated, OutputFormatterInterface $formatter) + { + if (!\is_array($sections)) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($sections) must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($sections) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_int($verbosity)) { + if (!(\is_bool($verbosity) || \is_numeric($verbosity))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($verbosity) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($verbosity) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $verbosity = (int) $verbosity; + } + } + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($decorated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + parent::__construct($stream, $verbosity, $decorated, $formatter); + \array_unshift($sections, $this); + $this->sections =& $sections; + $this->terminal = new Terminal(); + } + /** + * Clears previous output for this section. + * + * @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared + */ + public function clear($lines = null) + { + if (!\is_null($lines)) { + if (!\is_int($lines)) { + if (!(\is_bool($lines) || \is_numeric($lines))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($lines) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($lines) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $lines = (int) $lines; + } + } + } + if (empty($this->content) || !$this->isDecorated()) { + return; + } + if ($lines) { + \array_splice($this->content, -($lines * 2)); + // Multiply lines by 2 to cater for each new line added between content + } else { + $lines = $this->lines; + $this->content = []; + } + $this->lines -= $lines; + parent::doWrite($this->popStreamContentUntilCurrentSection($lines), \false); + } + /** + * Overwrites the previous output with a new message. + * + * @param array|string $message + */ + public function overwrite($message) + { + $this->clear(); + $this->writeln($message); + } + public function getContent() + { + $phabelReturn = \implode('', $this->content); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @internal + */ + public function addContent($input) + { + if (!\is_string($input)) { + if (!(\is_string($input) || \is_object($input) && \method_exists($input, '__toString') || (\is_bool($input) || \is_numeric($input)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($input) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($input) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $input = (string) $input; + } + } + foreach (\explode(\PHP_EOL, $input) as $lineContent) { + $this->lines += \ceil($this->getDisplayLength($lineContent) / $this->terminal->getWidth()) ?: 1; + $this->content[] = $lineContent; + $this->content[] = \PHP_EOL; + } + } + /** + * {@inheritdoc} + */ + protected function doWrite($message, $newline) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_bool($newline)) { + if (!(\is_bool($newline) || \is_numeric($newline) || \is_string($newline))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($newline) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $newline = (bool) $newline; + } + } + if (!$this->isDecorated()) { + parent::doWrite($message, $newline); + return; + } + $erasedContent = $this->popStreamContentUntilCurrentSection(); + $this->addContent($message); + parent::doWrite($message, \true); + parent::doWrite($erasedContent, \false); + } + /** + * At initial stage, cursor is at the end of stream output. This method makes cursor crawl upwards until it hits + * current section. Then it erases content it crawled through. Optionally, it erases part of current section too. + */ + private function popStreamContentUntilCurrentSection($numberOfLinesToClearFromCurrentSection = 0) + { + if (!\is_int($numberOfLinesToClearFromCurrentSection)) { + if (!(\is_bool($numberOfLinesToClearFromCurrentSection) || \is_numeric($numberOfLinesToClearFromCurrentSection))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($numberOfLinesToClearFromCurrentSection) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($numberOfLinesToClearFromCurrentSection) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $numberOfLinesToClearFromCurrentSection = (int) $numberOfLinesToClearFromCurrentSection; + } + } + $numberOfLinesToClear = $numberOfLinesToClearFromCurrentSection; + $erasedContent = []; + foreach ($this->sections as $section) { + if ($section === $this) { + break; + } + $numberOfLinesToClear += $section->lines; + $erasedContent[] = $section->getContent(); + } + if ($numberOfLinesToClear > 0) { + // move cursor up n lines + parent::doWrite(\sprintf("\x1b[%dA", $numberOfLinesToClear), \false); + // erase to end of screen + parent::doWrite("\x1b[0J", \false); + } + $phabelReturn = \implode('', \array_reverse($erasedContent)); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + private function getDisplayLength($text) + { + if (!\is_string($text)) { + if (!(\is_string($text) || \is_object($text) && \method_exists($text, '__toString') || (\is_bool($text) || \is_numeric($text)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($text) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($text) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $text = (string) $text; + } + } + $phabelReturn = Helper::width(Helper::removeDecoration($this->getFormatter(), \str_replace("\t", ' ', $text))); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Output/NullOutput.php b/vendor-bundle/symfony/console/Output/NullOutput.php new file mode 100644 index 000000000..6a74e06e1 --- /dev/null +++ b/vendor-bundle/symfony/console/Output/NullOutput.php @@ -0,0 +1,149 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Output; + +use Phabel\Symfony\Component\Console\Formatter\NullOutputFormatter; +use Phabel\Symfony\Component\Console\Formatter\OutputFormatterInterface; +/** + * NullOutput suppresses all output. + * + * $output = new NullOutput(); + * + * @author Fabien Potencier + * @author Tobias Schultze + */ +class NullOutput implements OutputInterface +{ + private $formatter; + /** + * {@inheritdoc} + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + // do nothing + } + /** + * {@inheritdoc} + */ + public function getFormatter() + { + if ($this->formatter) { + return $this->formatter; + } + // to comply with the interface we must return a OutputFormatterInterface + return $this->formatter = new NullOutputFormatter(); + } + /** + * {@inheritdoc} + */ + public function setDecorated($decorated) + { + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($decorated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + // do nothing + } + /** + * {@inheritdoc} + */ + public function isDecorated() + { + return \false; + } + /** + * {@inheritdoc} + */ + public function setVerbosity($level) + { + if (!\is_int($level)) { + if (!(\is_bool($level) || \is_numeric($level))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($level) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($level) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $level = (int) $level; + } + } + // do nothing + } + /** + * {@inheritdoc} + */ + public function getVerbosity() + { + return self::VERBOSITY_QUIET; + } + /** + * {@inheritdoc} + */ + public function isQuiet() + { + return \true; + } + /** + * {@inheritdoc} + */ + public function isVerbose() + { + return \false; + } + /** + * {@inheritdoc} + */ + public function isVeryVerbose() + { + return \false; + } + /** + * {@inheritdoc} + */ + public function isDebug() + { + return \false; + } + /** + * {@inheritdoc} + */ + public function writeln($messages, $options = self::OUTPUT_NORMAL) + { + if (!\is_int($options)) { + if (!(\is_bool($options) || \is_numeric($options))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($options) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($options) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $options = (int) $options; + } + } + // do nothing + } + /** + * {@inheritdoc} + */ + public function write($messages, $newline = \false, $options = self::OUTPUT_NORMAL) + { + if (!\is_bool($newline)) { + if (!(\is_bool($newline) || \is_numeric($newline) || \is_string($newline))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($newline) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $newline = (bool) $newline; + } + } + if (!\is_int($options)) { + if (!(\is_bool($options) || \is_numeric($options))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($options) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($options) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $options = (int) $options; + } + } + // do nothing + } +} diff --git a/vendor-bundle/symfony/console/Output/Output.php b/vendor-bundle/symfony/console/Output/Output.php new file mode 100644 index 000000000..b332daa35 --- /dev/null +++ b/vendor-bundle/symfony/console/Output/Output.php @@ -0,0 +1,204 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Output; + +use Phabel\Symfony\Component\Console\Formatter\OutputFormatter; +use Phabel\Symfony\Component\Console\Formatter\OutputFormatterInterface; +/** + * Base class for output classes. + * + * There are five levels of verbosity: + * + * * normal: no option passed (normal output) + * * verbose: -v (more output) + * * very verbose: -vv (highly extended output) + * * debug: -vvv (all debug output) + * * quiet: -q (no output) + * + * @author Fabien Potencier + */ +abstract class Output implements OutputInterface +{ + private $verbosity; + private $formatter; + /** + * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) + * @param bool $decorated Whether to decorate messages + * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) + */ + public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = \false, OutputFormatterInterface $formatter = null) + { + if (!\is_null($verbosity)) { + if (!\is_int($verbosity)) { + if (!(\is_bool($verbosity) || \is_numeric($verbosity))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($verbosity) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($verbosity) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $verbosity = (int) $verbosity; + } + } + } + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($decorated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity; + $this->formatter = isset($formatter) ? $formatter : new OutputFormatter(); + $this->formatter->setDecorated($decorated); + } + /** + * {@inheritdoc} + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + $this->formatter = $formatter; + } + /** + * {@inheritdoc} + */ + public function getFormatter() + { + return $this->formatter; + } + /** + * {@inheritdoc} + */ + public function setDecorated($decorated) + { + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($decorated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + $this->formatter->setDecorated($decorated); + } + /** + * {@inheritdoc} + */ + public function isDecorated() + { + return $this->formatter->isDecorated(); + } + /** + * {@inheritdoc} + */ + public function setVerbosity($level) + { + if (!\is_int($level)) { + if (!(\is_bool($level) || \is_numeric($level))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($level) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($level) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $level = (int) $level; + } + } + $this->verbosity = $level; + } + /** + * {@inheritdoc} + */ + public function getVerbosity() + { + return $this->verbosity; + } + /** + * {@inheritdoc} + */ + public function isQuiet() + { + return self::VERBOSITY_QUIET === $this->verbosity; + } + /** + * {@inheritdoc} + */ + public function isVerbose() + { + return self::VERBOSITY_VERBOSE <= $this->verbosity; + } + /** + * {@inheritdoc} + */ + public function isVeryVerbose() + { + return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity; + } + /** + * {@inheritdoc} + */ + public function isDebug() + { + return self::VERBOSITY_DEBUG <= $this->verbosity; + } + /** + * {@inheritdoc} + */ + public function writeln($messages, $options = self::OUTPUT_NORMAL) + { + if (!\is_int($options)) { + if (!(\is_bool($options) || \is_numeric($options))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($options) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($options) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $options = (int) $options; + } + } + $this->write($messages, \true, $options); + } + /** + * {@inheritdoc} + */ + public function write($messages, $newline = \false, $options = self::OUTPUT_NORMAL) + { + if (!\is_bool($newline)) { + if (!(\is_bool($newline) || \is_numeric($newline) || \is_string($newline))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($newline) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $newline = (bool) $newline; + } + } + if (!\is_int($options)) { + if (!(\is_bool($options) || \is_numeric($options))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($options) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($options) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $options = (int) $options; + } + } + if (!\is_iterable($messages)) { + $messages = [$messages]; + } + $types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN; + $type = $types & $options ?: self::OUTPUT_NORMAL; + $verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG; + $verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL; + if ($verbosity > $this->getVerbosity()) { + return; + } + foreach ($messages as $message) { + switch ($type) { + case OutputInterface::OUTPUT_NORMAL: + $message = $this->formatter->format($message); + break; + case OutputInterface::OUTPUT_RAW: + break; + case OutputInterface::OUTPUT_PLAIN: + $message = \strip_tags($this->formatter->format($message)); + break; + } + $this->doWrite(isset($message) ? $message : '', $newline); + } + } + /** + * Writes a message to the output. + */ + protected abstract function doWrite($message, $newline); +} diff --git a/vendor-bundle/symfony/console/Output/OutputInterface.php b/vendor-bundle/symfony/console/Output/OutputInterface.php new file mode 100644 index 000000000..4fd44caee --- /dev/null +++ b/vendor-bundle/symfony/console/Output/OutputInterface.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Output; + +use Phabel\Symfony\Component\Console\Formatter\OutputFormatterInterface; +/** + * OutputInterface is the interface implemented by all Output classes. + * + * @author Fabien Potencier + */ +interface OutputInterface +{ + const VERBOSITY_QUIET = 16; + const VERBOSITY_NORMAL = 32; + const VERBOSITY_VERBOSE = 64; + const VERBOSITY_VERY_VERBOSE = 128; + const VERBOSITY_DEBUG = 256; + const OUTPUT_NORMAL = 1; + const OUTPUT_RAW = 2; + const OUTPUT_PLAIN = 4; + /** + * Writes a message to the output. + * + * @param string|iterable $messages The message as an iterable of strings or a single string + * @param bool $newline Whether to add a newline + * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL + */ + public function write($messages, $newline = \false, $options = 0); + /** + * Writes a message to the output and adds a newline at the end. + * + * @param string|iterable $messages The message as an iterable of strings or a single string + * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL + */ + public function writeln($messages, $options = 0); + /** + * Sets the verbosity of the output. + */ + public function setVerbosity($level); + /** + * Gets the current verbosity of the output. + * + * @return int The current level of verbosity (one of the VERBOSITY constants) + */ + public function getVerbosity(); + /** + * Returns whether verbosity is quiet (-q). + * + * @return bool true if verbosity is set to VERBOSITY_QUIET, false otherwise + */ + public function isQuiet(); + /** + * Returns whether verbosity is verbose (-v). + * + * @return bool true if verbosity is set to VERBOSITY_VERBOSE, false otherwise + */ + public function isVerbose(); + /** + * Returns whether verbosity is very verbose (-vv). + * + * @return bool true if verbosity is set to VERBOSITY_VERY_VERBOSE, false otherwise + */ + public function isVeryVerbose(); + /** + * Returns whether verbosity is debug (-vvv). + * + * @return bool true if verbosity is set to VERBOSITY_DEBUG, false otherwise + */ + public function isDebug(); + /** + * Sets the decorated flag. + */ + public function setDecorated($decorated); + /** + * Gets the decorated flag. + * + * @return bool true if the output will decorate messages, false otherwise + */ + public function isDecorated(); + public function setFormatter(OutputFormatterInterface $formatter); + /** + * Returns current output formatter instance. + * + * @return OutputFormatterInterface + */ + public function getFormatter(); +} diff --git a/vendor-bundle/symfony/console/Output/StreamOutput.php b/vendor-bundle/symfony/console/Output/StreamOutput.php new file mode 100644 index 000000000..692ae06e8 --- /dev/null +++ b/vendor-bundle/symfony/console/Output/StreamOutput.php @@ -0,0 +1,127 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Output; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Formatter\OutputFormatterInterface; +/** + * StreamOutput writes the output to a given stream. + * + * Usage: + * + * $output = new StreamOutput(fopen('php://stdout', 'w')); + * + * As `StreamOutput` can use any stream, you can also use a file: + * + * $output = new StreamOutput(fopen('/path/to/output.log', 'a', false)); + * + * @author Fabien Potencier + */ +class StreamOutput extends Output +{ + private $stream; + /** + * @param resource $stream A stream resource + * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) + * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) + * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) + * + * @throws InvalidArgumentException When first argument is not a real stream + */ + public function __construct($stream, $verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null) + { + if (!\is_int($verbosity)) { + if (!(\is_bool($verbosity) || \is_numeric($verbosity))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($verbosity) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($verbosity) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $verbosity = (int) $verbosity; + } + } + if (!\is_null($decorated)) { + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($decorated) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + } + if (!\is_resource($stream) || 'stream' !== \get_resource_type($stream)) { + throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.'); + } + $this->stream = $stream; + if (null === $decorated) { + $decorated = $this->hasColorSupport(); + } + parent::__construct($verbosity, $decorated, $formatter); + } + /** + * Gets the stream attached to this StreamOutput instance. + * + * @return resource A stream resource + */ + public function getStream() + { + return $this->stream; + } + /** + * {@inheritdoc} + */ + protected function doWrite($message, $newline) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_bool($newline)) { + if (!(\is_bool($newline) || \is_numeric($newline) || \is_string($newline))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($newline) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $newline = (bool) $newline; + } + } + if ($newline) { + $message .= \PHP_EOL; + } + @\fwrite($this->stream, $message); + \fflush($this->stream); + } + /** + * Returns true if the stream supports colorization. + * + * Colorization is disabled if not supported by the stream: + * + * This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo + * terminals via named pipes, so we can only check the environment. + * + * Reference: Composer\XdebugHandler\Process::supportsColor + * https://github.com/composer/xdebug-handler + * + * @return bool true if the stream supports colorization, false otherwise + */ + protected function hasColorSupport() + { + // Follow https://no-color.org/ + if (isset($_SERVER['NO_COLOR']) || \false !== \getenv('NO_COLOR')) { + return \false; + } + if ('Hyper' === \getenv('TERM_PROGRAM')) { + return \true; + } + if (\DIRECTORY_SEPARATOR === '\\') { + return \function_exists('sapi_windows_vt100_support') && @\sapi_windows_vt100_support($this->stream) || \false !== \getenv('ANSICON') || 'ON' === \getenv('ConEmuANSI') || 'xterm' === \getenv('TERM'); + } + return \stream_isatty($this->stream); + } +} diff --git a/vendor-bundle/symfony/console/Output/TrimmedBufferOutput.php b/vendor-bundle/symfony/console/Output/TrimmedBufferOutput.php new file mode 100644 index 000000000..ed459b553 --- /dev/null +++ b/vendor-bundle/symfony/console/Output/TrimmedBufferOutput.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Output; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Formatter\OutputFormatterInterface; +/** + * A BufferedOutput that keeps only the last N chars. + * + * @author Jérémy Derussé + */ +class TrimmedBufferOutput extends Output +{ + private $maxLength; + private $buffer = ''; + public function __construct($maxLength, $verbosity = self::VERBOSITY_NORMAL, $decorated = \false, OutputFormatterInterface $formatter = null) + { + if (!\is_int($maxLength)) { + if (!(\is_bool($maxLength) || \is_numeric($maxLength))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($maxLength) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($maxLength) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $maxLength = (int) $maxLength; + } + } + if (!\is_null($verbosity)) { + if (!\is_int($verbosity)) { + if (!(\is_bool($verbosity) || \is_numeric($verbosity))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($verbosity) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($verbosity) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $verbosity = (int) $verbosity; + } + } + } + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($decorated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + if ($maxLength <= 0) { + throw new InvalidArgumentException(\sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); + } + parent::__construct($verbosity, $decorated, $formatter); + $this->maxLength = $maxLength; + } + /** + * Empties buffer and returns its content. + * + * @return string + */ + public function fetch() + { + $content = $this->buffer; + $this->buffer = ''; + return $content; + } + /** + * {@inheritdoc} + */ + protected function doWrite($message, $newline) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_bool($newline)) { + if (!(\is_bool($newline) || \is_numeric($newline) || \is_string($newline))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($newline) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $newline = (bool) $newline; + } + } + $this->buffer .= $message; + if ($newline) { + $this->buffer .= \PHP_EOL; + } + $this->buffer = \substr($this->buffer, 0 - $this->maxLength); + } +} diff --git a/vendor-bundle/symfony/console/Question/ChoiceQuestion.php b/vendor-bundle/symfony/console/Question/ChoiceQuestion.php new file mode 100644 index 000000000..4c1809c3c --- /dev/null +++ b/vendor-bundle/symfony/console/Question/ChoiceQuestion.php @@ -0,0 +1,192 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Question; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * Represents a choice question. + * + * @author Fabien Potencier + */ +class ChoiceQuestion extends Question +{ + private $choices; + private $multiselect = \false; + private $prompt = ' > '; + private $errorMessage = 'Value "%s" is invalid'; + /** + * @param string $question The question to ask to the user + * @param array $choices The list of available choices + * @param mixed $default The default answer to return + */ + public function __construct($question, $choices, $default = null) + { + if (!\is_array($choices)) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($choices) must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($choices) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_string($question)) { + if (!(\is_string($question) || \is_object($question) && \method_exists($question, '__toString') || (\is_bool($question) || \is_numeric($question)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($question) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($question) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $question = (string) $question; + } + } + if (!$choices) { + throw new \LogicException('Choice question must have at least 1 choice available.'); + } + parent::__construct($question, $default); + $this->choices = $choices; + $this->setValidator($this->getDefaultValidator()); + $this->setAutocompleterValues($choices); + } + /** + * Returns available choices. + * + * @return array + */ + public function getChoices() + { + return $this->choices; + } + /** + * Sets multiselect option. + * + * When multiselect is set to true, multiple choices can be answered. + * + * @return $this + */ + public function setMultiselect($multiselect) + { + if (!\is_bool($multiselect)) { + if (!(\is_bool($multiselect) || \is_numeric($multiselect) || \is_string($multiselect))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($multiselect) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($multiselect) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $multiselect = (bool) $multiselect; + } + } + $this->multiselect = $multiselect; + $this->setValidator($this->getDefaultValidator()); + return $this; + } + /** + * Returns whether the choices are multiselect. + * + * @return bool + */ + public function isMultiselect() + { + return $this->multiselect; + } + /** + * Gets the prompt for choices. + * + * @return string + */ + public function getPrompt() + { + return $this->prompt; + } + /** + * Sets the prompt for choices. + * + * @return $this + */ + public function setPrompt($prompt) + { + if (!\is_string($prompt)) { + if (!(\is_string($prompt) || \is_object($prompt) && \method_exists($prompt, '__toString') || (\is_bool($prompt) || \is_numeric($prompt)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($prompt) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($prompt) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $prompt = (string) $prompt; + } + } + $this->prompt = $prompt; + return $this; + } + /** + * Sets the error message for invalid values. + * + * The error message has a string placeholder (%s) for the invalid value. + * + * @return $this + */ + public function setErrorMessage($errorMessage) + { + if (!\is_string($errorMessage)) { + if (!(\is_string($errorMessage) || \is_object($errorMessage) && \method_exists($errorMessage, '__toString') || (\is_bool($errorMessage) || \is_numeric($errorMessage)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($errorMessage) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($errorMessage) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $errorMessage = (string) $errorMessage; + } + } + $this->errorMessage = $errorMessage; + $this->setValidator($this->getDefaultValidator()); + return $this; + } + private function getDefaultValidator() + { + $choices = $this->choices; + $errorMessage = $this->errorMessage; + $multiselect = $this->multiselect; + $isAssoc = $this->isAssoc($choices); + $phabelReturn = function ($selected) use($choices, $errorMessage, $multiselect, $isAssoc) { + if ($multiselect) { + // Check for a separated comma values + if (!\preg_match('/^[^,]+(?:,[^,]+)*$/', $selected, $matches)) { + throw new InvalidArgumentException(\sprintf($errorMessage, $selected)); + } + $selectedChoices = \explode(',', $selected); + } else { + $selectedChoices = [$selected]; + } + if ($this->isTrimmable()) { + foreach ($selectedChoices as $k => $v) { + $selectedChoices[$k] = \trim($v); + } + } + $multiselectChoices = []; + foreach ($selectedChoices as $value) { + $results = []; + foreach ($choices as $key => $choice) { + if ($choice === $value) { + $results[] = $key; + } + } + if (\count($results) > 1) { + throw new InvalidArgumentException(\sprintf('The provided answer is ambiguous. Value should be one of "%s".', \implode('" or "', $results))); + } + $result = \array_search($value, $choices); + if (!$isAssoc) { + if (\false !== $result) { + $result = $choices[$result]; + } elseif (isset($choices[$value])) { + $result = $choices[$value]; + } + } elseif (\false === $result && isset($choices[$value])) { + $result = $value; + } + if (\false === $result) { + throw new InvalidArgumentException(\sprintf($errorMessage, $value)); + } + // For associative choices, consistently return the key as string: + $multiselectChoices[] = $isAssoc ? (string) $result : $result; + } + if ($multiselect) { + return $multiselectChoices; + } + return \current($multiselectChoices); + }; + if (!\is_callable($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Question/ConfirmationQuestion.php b/vendor-bundle/symfony/console/Question/ConfirmationQuestion.php new file mode 100644 index 000000000..6aa9233c7 --- /dev/null +++ b/vendor-bundle/symfony/console/Question/ConfirmationQuestion.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Question; + +/** + * Represents a yes/no question. + * + * @author Fabien Potencier + */ +class ConfirmationQuestion extends Question +{ + private $trueAnswerRegex; + /** + * @param string $question The question to ask to the user + * @param bool $default The default answer to return, true or false + * @param string $trueAnswerRegex A regex to match the "yes" answer + */ + public function __construct($question, $default = \true, $trueAnswerRegex = '/^y/i') + { + if (!\is_string($question)) { + if (!(\is_string($question) || \is_object($question) && \method_exists($question, '__toString') || (\is_bool($question) || \is_numeric($question)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($question) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($question) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $question = (string) $question; + } + } + if (!\is_bool($default)) { + if (!(\is_bool($default) || \is_numeric($default) || \is_string($default))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($default) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($default) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $default = (bool) $default; + } + } + if (!\is_string($trueAnswerRegex)) { + if (!(\is_string($trueAnswerRegex) || \is_object($trueAnswerRegex) && \method_exists($trueAnswerRegex, '__toString') || (\is_bool($trueAnswerRegex) || \is_numeric($trueAnswerRegex)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($trueAnswerRegex) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($trueAnswerRegex) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $trueAnswerRegex = (string) $trueAnswerRegex; + } + } + parent::__construct($question, $default); + $this->trueAnswerRegex = $trueAnswerRegex; + $this->setNormalizer($this->getDefaultNormalizer()); + } + /** + * Returns the default answer normalizer. + */ + private function getDefaultNormalizer() + { + $default = $this->getDefault(); + $regex = $this->trueAnswerRegex; + $phabelReturn = function ($answer) use($default, $regex) { + if (\is_bool($answer)) { + return $answer; + } + $answerIsTrue = (bool) \preg_match($regex, $answer); + if (\false === $default) { + return $answer && $answerIsTrue; + } + return '' === $answer || $answerIsTrue; + }; + if (!\is_callable($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Question/Question.php b/vendor-bundle/symfony/console/Question/Question.php new file mode 100644 index 000000000..bd982031f --- /dev/null +++ b/vendor-bundle/symfony/console/Question/Question.php @@ -0,0 +1,343 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Question; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Exception\LogicException; +/** + * Represents a Question. + * + * @author Fabien Potencier + */ +class Question +{ + private $question; + private $attempts; + private $hidden = \false; + private $hiddenFallback = \true; + private $autocompleterCallback; + private $validator; + private $default; + private $normalizer; + private $trimmable = \true; + private $multiline = \false; + /** + * @param string $question The question to ask to the user + * @param string|bool|int|float|null $default The default answer to return if the user enters nothing + */ + public function __construct($question, $default = null) + { + if (!\is_string($question)) { + if (!(\is_string($question) || \is_object($question) && \method_exists($question, '__toString') || (\is_bool($question) || \is_numeric($question)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($question) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($question) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $question = (string) $question; + } + } + $this->question = $question; + $this->default = $default; + } + /** + * Returns the question. + * + * @return string + */ + public function getQuestion() + { + return $this->question; + } + /** + * Returns the default answer. + * + * @return string|bool|int|float|null + */ + public function getDefault() + { + return $this->default; + } + /** + * Returns whether the user response accepts newline characters. + */ + public function isMultiline() + { + $phabelReturn = $this->multiline; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Sets whether the user response should accept newline characters. + * + * @return $this + */ + public function setMultiline($multiline) + { + if (!\is_bool($multiline)) { + if (!(\is_bool($multiline) || \is_numeric($multiline) || \is_string($multiline))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($multiline) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($multiline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $multiline = (bool) $multiline; + } + } + $this->multiline = $multiline; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Returns whether the user response must be hidden. + * + * @return bool + */ + public function isHidden() + { + return $this->hidden; + } + /** + * Sets whether the user response must be hidden or not. + * + * @return $this + * + * @throws LogicException In case the autocompleter is also used + */ + public function setHidden($hidden) + { + if (!\is_bool($hidden)) { + if (!(\is_bool($hidden) || \is_numeric($hidden) || \is_string($hidden))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($hidden) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($hidden) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $hidden = (bool) $hidden; + } + } + if ($this->autocompleterCallback) { + throw new LogicException('A hidden question cannot use the autocompleter.'); + } + $this->hidden = (bool) $hidden; + return $this; + } + /** + * In case the response can not be hidden, whether to fallback on non-hidden question or not. + * + * @return bool + */ + public function isHiddenFallback() + { + return $this->hiddenFallback; + } + /** + * Sets whether to fallback on non-hidden question if the response can not be hidden. + * + * @return $this + */ + public function setHiddenFallback($fallback) + { + if (!\is_bool($fallback)) { + if (!(\is_bool($fallback) || \is_numeric($fallback) || \is_string($fallback))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($fallback) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($fallback) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $fallback = (bool) $fallback; + } + } + $this->hiddenFallback = (bool) $fallback; + return $this; + } + /** + * Gets values for the autocompleter. + * + * @return iterable|null + */ + public function getAutocompleterValues() + { + $callback = $this->getAutocompleterCallback(); + return $callback ? $callback('') : null; + } + /** + * Sets values for the autocompleter. + * + * @return $this + * + * @throws LogicException + */ + public function setAutocompleterValues($values) + { + if (!(\is_array($values) || $values instanceof \Traversable || \is_null($values))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($values) must be of type ?iterable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($values) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (\is_array($values)) { + $values = $this->isAssoc($values) ? \array_merge(\array_keys($values), \array_values($values)) : \array_values($values); + $callback = static function () use($values) { + return $values; + }; + } elseif ($values instanceof \Traversable) { + $valueCache = null; + $callback = static function () use($values, &$valueCache) { + return isset($valueCache) ? $valueCache : ($valueCache = \iterator_to_array($values, \false)); + }; + } else { + $callback = null; + } + return $this->setAutocompleterCallback($callback); + } + /** + * Gets the callback function used for the autocompleter. + */ + public function getAutocompleterCallback() + { + $phabelReturn = $this->autocompleterCallback; + if (!(\is_callable($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?callable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Sets the callback function used for the autocompleter. + * + * The callback is passed the user input as argument and should return an iterable of corresponding suggestions. + * + * @return $this + */ + public function setAutocompleterCallback(callable $callback = null) + { + if ($this->hidden && null !== $callback) { + throw new LogicException('A hidden question cannot use the autocompleter.'); + } + $this->autocompleterCallback = $callback; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Sets a validator for the question. + * + * @return $this + */ + public function setValidator(callable $validator = null) + { + $this->validator = $validator; + return $this; + } + /** + * Gets the validator for the question. + * + * @return callable|null + */ + public function getValidator() + { + return $this->validator; + } + /** + * Sets the maximum number of attempts. + * + * Null means an unlimited number of attempts. + * + * @return $this + * + * @throws InvalidArgumentException in case the number of attempts is invalid + */ + public function setMaxAttempts($attempts) + { + if (!\is_null($attempts)) { + if (!\is_int($attempts)) { + if (!(\is_bool($attempts) || \is_numeric($attempts))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($attempts) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($attempts) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $attempts = (int) $attempts; + } + } + } + if (null !== $attempts) { + $attempts = (int) $attempts; + if ($attempts < 1) { + throw new InvalidArgumentException('Maximum number of attempts must be a positive value.'); + } + } + $this->attempts = $attempts; + return $this; + } + /** + * Gets the maximum number of attempts. + * + * Null means an unlimited number of attempts. + * + * @return int|null + */ + public function getMaxAttempts() + { + return $this->attempts; + } + /** + * Sets a normalizer for the response. + * + * The normalizer can be a callable (a string), a closure or a class implementing __invoke. + * + * @return $this + */ + public function setNormalizer(callable $normalizer) + { + $this->normalizer = $normalizer; + return $this; + } + /** + * Gets the normalizer for the response. + * + * The normalizer can ba a callable (a string), a closure or a class implementing __invoke. + * + * @return callable|null + */ + public function getNormalizer() + { + return $this->normalizer; + } + protected function isAssoc(array $array) + { + return (bool) \count(\array_filter(\array_keys($array), 'is_string')); + } + public function isTrimmable() + { + $phabelReturn = $this->trimmable; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return $this + */ + public function setTrimmable($trimmable) + { + if (!\is_bool($trimmable)) { + if (!(\is_bool($trimmable) || \is_numeric($trimmable) || \is_string($trimmable))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($trimmable) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($trimmable) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $trimmable = (bool) $trimmable; + } + } + $this->trimmable = $trimmable; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Resources/bin/hiddeninput.exe b/vendor-bundle/symfony/console/Resources/bin/hiddeninput.exe new file mode 100644 index 000000000..c8cf65e8d Binary files /dev/null and b/vendor-bundle/symfony/console/Resources/bin/hiddeninput.exe differ diff --git a/vendor-bundle/symfony/console/SignalRegistry/SignalRegistry.php b/vendor-bundle/symfony/console/SignalRegistry/SignalRegistry.php new file mode 100644 index 000000000..582f6321e --- /dev/null +++ b/vendor-bundle/symfony/console/SignalRegistry/SignalRegistry.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\SignalRegistry; + +final class SignalRegistry +{ + private $signalHandlers = []; + public function __construct() + { + if (\function_exists('pcntl_async_signals')) { + \pcntl_async_signals(\true); + } + } + public function register($signal, callable $signalHandler) + { + if (!\is_int($signal)) { + if (!(\is_bool($signal) || \is_numeric($signal))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($signal) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signal) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signal = (int) $signal; + } + } + if (!isset($this->signalHandlers[$signal])) { + $previousCallback = \pcntl_signal_get_handler($signal); + if (\is_callable($previousCallback)) { + $this->signalHandlers[$signal][] = $previousCallback; + } + } + $this->signalHandlers[$signal][] = $signalHandler; + \pcntl_signal($signal, [$this, 'handle']); + } + public static function isSupported() + { + if (!\function_exists('pcntl_signal')) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if (\in_array('pcntl_signal', \explode(',', \ini_get('disable_functions')))) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @internal + */ + public function handle($signal) + { + if (!\is_int($signal)) { + if (!(\is_bool($signal) || \is_numeric($signal))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($signal) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signal) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signal = (int) $signal; + } + } + $count = \count($this->signalHandlers[$signal]); + foreach ($this->signalHandlers[$signal] as $i => $signalHandler) { + $hasNext = $i !== $count - 1; + $signalHandler($signal, $hasNext); + } + } +} diff --git a/vendor-bundle/symfony/console/SingleCommandApplication.php b/vendor-bundle/symfony/console/SingleCommandApplication.php new file mode 100644 index 000000000..8654cf0fa --- /dev/null +++ b/vendor-bundle/symfony/console/SingleCommandApplication.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console; + +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Grégoire Pineau + */ +class SingleCommandApplication extends Command +{ + private $version = 'UNKNOWN'; + private $autoExit = \true; + private $running = \false; + public function setVersion($version) + { + if (!\is_string($version)) { + if (!(\is_string($version) || \is_object($version) && \method_exists($version, '__toString') || (\is_bool($version) || \is_numeric($version)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($version) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($version) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $version = (string) $version; + } + } + $this->version = $version; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @final + */ + public function setAutoExit($autoExit) + { + if (!\is_bool($autoExit)) { + if (!(\is_bool($autoExit) || \is_numeric($autoExit) || \is_string($autoExit))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($autoExit) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($autoExit) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $autoExit = (bool) $autoExit; + } + } + $this->autoExit = $autoExit; + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function run(InputInterface $input = null, OutputInterface $output = null) + { + if ($this->running) { + $phabelReturn = parent::run($input, $output); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + // We use the command name as the application name + $application = new Application($this->getName() ?: 'UNKNOWN', $this->version); + $application->setAutoExit($this->autoExit); + // Fix the usage of the command displayed with "--help" + $this->setName($_SERVER['argv'][0]); + $application->add($this); + $application->setDefaultCommand($this->getName(), \true); + $this->running = \true; + try { + $ret = $application->run($input, $output); + } finally { + $this->running = \false; + } + $phabelReturn = isset($ret) ? $ret : 1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Style/OutputStyle.php b/vendor-bundle/symfony/console/Style/OutputStyle.php new file mode 100644 index 000000000..bd75f4a6d --- /dev/null +++ b/vendor-bundle/symfony/console/Style/OutputStyle.php @@ -0,0 +1,183 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Style; + +use Phabel\Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Phabel\Symfony\Component\Console\Helper\ProgressBar; +use Phabel\Symfony\Component\Console\Output\ConsoleOutputInterface; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +/** + * Decorates output to add console style guide helpers. + * + * @author Kevin Bond + */ +abstract class OutputStyle implements OutputInterface, StyleInterface +{ + private $output; + public function __construct(OutputInterface $output) + { + $this->output = $output; + } + /** + * {@inheritdoc} + */ + public function newLine($count = 1) + { + if (!\is_int($count)) { + if (!(\is_bool($count) || \is_numeric($count))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($count) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($count) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $count = (int) $count; + } + } + $this->output->write(\str_repeat(\PHP_EOL, $count)); + } + /** + * @return ProgressBar + */ + public function createProgressBar($max = 0) + { + if (!\is_int($max)) { + if (!(\is_bool($max) || \is_numeric($max))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($max) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($max) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $max = (int) $max; + } + } + return new ProgressBar($this->output, $max); + } + /** + * {@inheritdoc} + */ + public function write($messages, $newline = \false, $type = self::OUTPUT_NORMAL) + { + if (!\is_bool($newline)) { + if (!(\is_bool($newline) || \is_numeric($newline) || \is_string($newline))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($newline) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $newline = (bool) $newline; + } + } + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + $this->output->write($messages, $newline, $type); + } + /** + * {@inheritdoc} + */ + public function writeln($messages, $type = self::OUTPUT_NORMAL) + { + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + $this->output->writeln($messages, $type); + } + /** + * {@inheritdoc} + */ + public function setVerbosity($level) + { + if (!\is_int($level)) { + if (!(\is_bool($level) || \is_numeric($level))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($level) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($level) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $level = (int) $level; + } + } + $this->output->setVerbosity($level); + } + /** + * {@inheritdoc} + */ + public function getVerbosity() + { + return $this->output->getVerbosity(); + } + /** + * {@inheritdoc} + */ + public function setDecorated($decorated) + { + if (!\is_bool($decorated)) { + if (!(\is_bool($decorated) || \is_numeric($decorated) || \is_string($decorated))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($decorated) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($decorated) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $decorated = (bool) $decorated; + } + } + $this->output->setDecorated($decorated); + } + /** + * {@inheritdoc} + */ + public function isDecorated() + { + return $this->output->isDecorated(); + } + /** + * {@inheritdoc} + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + $this->output->setFormatter($formatter); + } + /** + * {@inheritdoc} + */ + public function getFormatter() + { + return $this->output->getFormatter(); + } + /** + * {@inheritdoc} + */ + public function isQuiet() + { + return $this->output->isQuiet(); + } + /** + * {@inheritdoc} + */ + public function isVerbose() + { + return $this->output->isVerbose(); + } + /** + * {@inheritdoc} + */ + public function isVeryVerbose() + { + return $this->output->isVeryVerbose(); + } + /** + * {@inheritdoc} + */ + public function isDebug() + { + return $this->output->isDebug(); + } + protected function getErrorOutput() + { + if (!$this->output instanceof ConsoleOutputInterface) { + return $this->output; + } + return $this->output->getErrorOutput(); + } +} diff --git a/vendor-bundle/symfony/console/Style/StyleInterface.php b/vendor-bundle/symfony/console/Style/StyleInterface.php new file mode 100644 index 000000000..d052820d2 --- /dev/null +++ b/vendor-bundle/symfony/console/Style/StyleInterface.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Style; + +/** + * Output style helpers. + * + * @author Kevin Bond + */ +interface StyleInterface +{ + /** + * Formats a command title. + */ + public function title($message); + /** + * Formats a section title. + */ + public function section($message); + /** + * Formats a list. + */ + public function listing(array $elements); + /** + * Formats informational text. + * + * @param string|array $message + */ + public function text($message); + /** + * Formats a success result bar. + * + * @param string|array $message + */ + public function success($message); + /** + * Formats an error result bar. + * + * @param string|array $message + */ + public function error($message); + /** + * Formats an warning result bar. + * + * @param string|array $message + */ + public function warning($message); + /** + * Formats a note admonition. + * + * @param string|array $message + */ + public function note($message); + /** + * Formats a caution admonition. + * + * @param string|array $message + */ + public function caution($message); + /** + * Formats a table. + */ + public function table(array $headers, array $rows); + /** + * Asks a question. + * + * @return mixed + */ + public function ask($question, $default = null, callable $validator = null); + /** + * Asks a question with the user input hidden. + * + * @return mixed + */ + public function askHidden($question, callable $validator = null); + /** + * Asks for confirmation. + * + * @return bool + */ + public function confirm($question, $default = \true); + /** + * Asks a choice question. + * + * @param string|int|null $default + * + * @return mixed + */ + public function choice($question, array $choices, $default = null); + /** + * Add newline(s). + */ + public function newLine($count = 1); + /** + * Starts the progress output. + */ + public function progressStart($max = 0); + /** + * Advances the progress output X steps. + */ + public function progressAdvance($step = 1); + /** + * Finishes the progress output. + */ + public function progressFinish(); +} diff --git a/vendor-bundle/symfony/console/Style/SymfonyStyle.php b/vendor-bundle/symfony/console/Style/SymfonyStyle.php new file mode 100644 index 000000000..934afe5d0 --- /dev/null +++ b/vendor-bundle/symfony/console/Style/SymfonyStyle.php @@ -0,0 +1,655 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Style; + +use Phabel\Symfony\Component\Console\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Console\Exception\RuntimeException; +use Phabel\Symfony\Component\Console\Formatter\OutputFormatter; +use Phabel\Symfony\Component\Console\Helper\Helper; +use Phabel\Symfony\Component\Console\Helper\ProgressBar; +use Phabel\Symfony\Component\Console\Helper\SymfonyQuestionHelper; +use Phabel\Symfony\Component\Console\Helper\Table; +use Phabel\Symfony\Component\Console\Helper\TableCell; +use Phabel\Symfony\Component\Console\Helper\TableSeparator; +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +use Phabel\Symfony\Component\Console\Output\TrimmedBufferOutput; +use Phabel\Symfony\Component\Console\Question\ChoiceQuestion; +use Phabel\Symfony\Component\Console\Question\ConfirmationQuestion; +use Phabel\Symfony\Component\Console\Question\Question; +use Phabel\Symfony\Component\Console\Terminal; +/** + * Output decorator helpers for the Symfony Style Guide. + * + * @author Kevin Bond + */ +class SymfonyStyle extends OutputStyle +{ + const MAX_LINE_LENGTH = 120; + private $input; + private $questionHelper; + private $progressBar; + private $lineLength; + private $bufferedOutput; + public function __construct(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), \false, clone $output->getFormatter()); + // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. + $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH; + $this->lineLength = \min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH); + parent::__construct($output); + } + /** + * Formats a message as a block of text. + * + * @param string|array $messages The message to write in the block + */ + public function block($messages, $type = null, $style = null, $prefix = ' ', $padding = \false, $escape = \true) + { + if (!\is_null($type)) { + if (!\is_string($type)) { + if (!(\is_string($type) || \is_object($type) && \method_exists($type, '__toString') || (\is_bool($type) || \is_numeric($type)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($type) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (string) $type; + } + } + } + if (!\is_null($style)) { + if (!\is_string($style)) { + if (!(\is_string($style) || \is_object($style) && \method_exists($style, '__toString') || (\is_bool($style) || \is_numeric($style)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($style) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($style) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $style = (string) $style; + } + } + } + if (!\is_string($prefix)) { + if (!(\is_string($prefix) || \is_object($prefix) && \method_exists($prefix, '__toString') || (\is_bool($prefix) || \is_numeric($prefix)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($prefix) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($prefix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $prefix = (string) $prefix; + } + } + if (!\is_bool($padding)) { + if (!(\is_bool($padding) || \is_numeric($padding) || \is_string($padding))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($padding) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($padding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $padding = (bool) $padding; + } + } + if (!\is_bool($escape)) { + if (!(\is_bool($escape) || \is_numeric($escape) || \is_string($escape))) { + throw new \TypeError(__METHOD__ . '(): Argument #6 ($escape) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($escape) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $escape = (bool) $escape; + } + } + $messages = \is_array($messages) ? \array_values($messages) : [$messages]; + $this->autoPrependBlock(); + $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape)); + $this->newLine(); + } + /** + * {@inheritdoc} + */ + public function title($message) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + $this->autoPrependBlock(); + $this->writeln([\sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), \sprintf('%s', \str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message))))]); + $this->newLine(); + } + /** + * {@inheritdoc} + */ + public function section($message) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + $this->autoPrependBlock(); + $this->writeln([\sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), \sprintf('%s', \str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message))))]); + $this->newLine(); + } + /** + * {@inheritdoc} + */ + public function listing(array $elements) + { + $this->autoPrependText(); + $elements = \array_map(function ($element) { + return \sprintf(' * %s', $element); + }, $elements); + $this->writeln($elements); + $this->newLine(); + } + /** + * {@inheritdoc} + */ + public function text($message) + { + $this->autoPrependText(); + $messages = \is_array($message) ? \array_values($message) : [$message]; + foreach ($messages as $message) { + $this->writeln(\sprintf(' %s', $message)); + } + } + /** + * Formats a command comment. + * + * @param string|array $message + */ + public function comment($message) + { + $this->block($message, null, null, ' // ', \false, \false); + } + /** + * {@inheritdoc} + */ + public function success($message) + { + $this->block($message, 'OK', 'fg=black;bg=green', ' ', \true); + } + /** + * {@inheritdoc} + */ + public function error($message) + { + $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', \true); + } + /** + * {@inheritdoc} + */ + public function warning($message) + { + $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', \true); + } + /** + * {@inheritdoc} + */ + public function note($message) + { + $this->block($message, 'NOTE', 'fg=yellow', ' ! '); + } + /** + * Formats an info message. + * + * @param string|array $message + */ + public function info($message) + { + $this->block($message, 'INFO', 'fg=green', ' ', \true); + } + /** + * {@inheritdoc} + */ + public function caution($message) + { + $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', \true); + } + /** + * {@inheritdoc} + */ + public function table(array $headers, array $rows) + { + $style = clone Table::getStyleDefinition('symfony-style-guide'); + $style->setCellHeaderFormat('%s'); + $table = new Table($this); + $table->setHeaders($headers); + $table->setRows($rows); + $table->setStyle($style); + $table->render(); + $this->newLine(); + } + /** + * Formats a horizontal table. + */ + public function horizontalTable(array $headers, array $rows) + { + $style = clone Table::getStyleDefinition('symfony-style-guide'); + $style->setCellHeaderFormat('%s'); + $table = new Table($this); + $table->setHeaders($headers); + $table->setRows($rows); + $table->setStyle($style); + $table->setHorizontal(\true); + $table->render(); + $this->newLine(); + } + /** + * Formats a list of key/value horizontally. + * + * Each row can be one of: + * * 'A title' + * * ['key' => 'value'] + * * new TableSeparator() + * + * @param string|array|TableSeparator ...$list + */ + public function definitionList(...$list) + { + $style = clone Table::getStyleDefinition('symfony-style-guide'); + $style->setCellHeaderFormat('%s'); + $table = new Table($this); + $headers = []; + $row = []; + foreach ($list as $value) { + if ($value instanceof TableSeparator) { + $headers[] = $value; + $row[] = $value; + continue; + } + if (\is_string($value)) { + $headers[] = new TableCell($value, ['colspan' => 2]); + $row[] = null; + continue; + } + if (!\is_array($value)) { + throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.'); + } + $headers[] = \key($value); + $row[] = \current($value); + } + $table->setHeaders($headers); + $table->setRows([$row]); + $table->setHorizontal(); + $table->setStyle($style); + $table->render(); + $this->newLine(); + } + /** + * {@inheritdoc} + */ + public function ask($question, $default = null, callable $validator = null) + { + if (!\is_string($question)) { + if (!(\is_string($question) || \is_object($question) && \method_exists($question, '__toString') || (\is_bool($question) || \is_numeric($question)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($question) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($question) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $question = (string) $question; + } + } + if (!\is_null($default)) { + if (!\is_string($default)) { + if (!(\is_string($default) || \is_object($default) && \method_exists($default, '__toString') || (\is_bool($default) || \is_numeric($default)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($default) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($default) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $default = (string) $default; + } + } + } + $question = new Question($question, $default); + $question->setValidator($validator); + return $this->askQuestion($question); + } + /** + * {@inheritdoc} + */ + public function askHidden($question, callable $validator = null) + { + if (!\is_string($question)) { + if (!(\is_string($question) || \is_object($question) && \method_exists($question, '__toString') || (\is_bool($question) || \is_numeric($question)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($question) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($question) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $question = (string) $question; + } + } + $question = new Question($question); + $question->setHidden(\true); + $question->setValidator($validator); + return $this->askQuestion($question); + } + /** + * {@inheritdoc} + */ + public function confirm($question, $default = \true) + { + if (!\is_string($question)) { + if (!(\is_string($question) || \is_object($question) && \method_exists($question, '__toString') || (\is_bool($question) || \is_numeric($question)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($question) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($question) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $question = (string) $question; + } + } + if (!\is_bool($default)) { + if (!(\is_bool($default) || \is_numeric($default) || \is_string($default))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($default) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($default) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $default = (bool) $default; + } + } + return $this->askQuestion(new ConfirmationQuestion($question, $default)); + } + /** + * {@inheritdoc} + */ + public function choice($question, array $choices, $default = null) + { + if (!\is_string($question)) { + if (!(\is_string($question) || \is_object($question) && \method_exists($question, '__toString') || (\is_bool($question) || \is_numeric($question)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($question) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($question) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $question = (string) $question; + } + } + if (null !== $default) { + $values = \array_flip($choices); + $default = isset($values[$default]) ? $values[$default] : $default; + } + return $this->askQuestion(new ChoiceQuestion($question, $choices, $default)); + } + /** + * {@inheritdoc} + */ + public function progressStart($max = 0) + { + if (!\is_int($max)) { + if (!(\is_bool($max) || \is_numeric($max))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($max) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($max) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $max = (int) $max; + } + } + $this->progressBar = $this->createProgressBar($max); + $this->progressBar->start(); + } + /** + * {@inheritdoc} + */ + public function progressAdvance($step = 1) + { + if (!\is_int($step)) { + if (!(\is_bool($step) || \is_numeric($step))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($step) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($step) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $step = (int) $step; + } + } + $this->getProgressBar()->advance($step); + } + /** + * {@inheritdoc} + */ + public function progressFinish() + { + $this->getProgressBar()->finish(); + $this->newLine(2); + $this->progressBar = null; + } + /** + * {@inheritdoc} + */ + public function createProgressBar($max = 0) + { + if (!\is_int($max)) { + if (!(\is_bool($max) || \is_numeric($max))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($max) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($max) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $max = (int) $max; + } + } + $progressBar = parent::createProgressBar($max); + if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === \getenv('TERM_PROGRAM')) { + $progressBar->setEmptyBarCharacter('░'); + // light shade character \u2591 + $progressBar->setProgressCharacter(''); + $progressBar->setBarCharacter('▓'); + // dark shade character \u2593 + } + return $progressBar; + } + /** + * @return mixed + */ + public function askQuestion(Question $question) + { + if ($this->input->isInteractive()) { + $this->autoPrependBlock(); + } + if (!$this->questionHelper) { + $this->questionHelper = new SymfonyQuestionHelper(); + } + $answer = $this->questionHelper->ask($this->input, $this, $question); + if ($this->input->isInteractive()) { + $this->newLine(); + $this->bufferedOutput->write("\n"); + } + return $answer; + } + /** + * {@inheritdoc} + */ + public function writeln($messages, $type = self::OUTPUT_NORMAL) + { + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + if (!\is_iterable($messages)) { + $messages = [$messages]; + } + foreach ($messages as $message) { + parent::writeln($message, $type); + $this->writeBuffer($message, \true, $type); + } + } + /** + * {@inheritdoc} + */ + public function write($messages, $newline = \false, $type = self::OUTPUT_NORMAL) + { + if (!\is_bool($newline)) { + if (!(\is_bool($newline) || \is_numeric($newline) || \is_string($newline))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($newline) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $newline = (bool) $newline; + } + } + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + if (!\is_iterable($messages)) { + $messages = [$messages]; + } + foreach ($messages as $message) { + parent::write($message, $newline, $type); + $this->writeBuffer($message, $newline, $type); + } + } + /** + * {@inheritdoc} + */ + public function newLine($count = 1) + { + if (!\is_int($count)) { + if (!(\is_bool($count) || \is_numeric($count))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($count) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($count) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $count = (int) $count; + } + } + parent::newLine($count); + $this->bufferedOutput->write(\str_repeat("\n", $count)); + } + /** + * Returns a new instance which makes use of stderr if available. + * + * @return self + */ + public function getErrorStyle() + { + return new self($this->input, $this->getErrorOutput()); + } + private function getProgressBar() + { + if (!$this->progressBar) { + throw new RuntimeException('The ProgressBar is not started.'); + } + $phabelReturn = $this->progressBar; + if (!$phabelReturn instanceof ProgressBar) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ProgressBar, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function autoPrependBlock() + { + $chars = \substr(\str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2); + if (!isset($chars[0])) { + $this->newLine(); + //empty history, so we should start with a new line. + return; + } + //Prepend new line for each non LF chars (This means no blank line was output before) + $this->newLine(2 - \substr_count($chars, "\n")); + } + private function autoPrependText() + { + $fetched = $this->bufferedOutput->fetch(); + //Prepend new line if last char isn't EOL: + if (!\str_ends_with($fetched, "\n")) { + $this->newLine(); + } + } + private function writeBuffer($message, $newLine, $type) + { + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + if (!\is_bool($newLine)) { + if (!(\is_bool($newLine) || \is_numeric($newLine) || \is_string($newLine))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($newLine) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newLine) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $newLine = (bool) $newLine; + } + } + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + // We need to know if the last chars are PHP_EOL + $this->bufferedOutput->write($message, $newLine, $type); + } + private function createBlock($messages, $type = null, $style = null, $prefix = ' ', $padding = \false, $escape = \false) + { + if (!(\is_array($messages) || $messages instanceof \Traversable)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($messages) must be of type iterable, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($messages) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_null($type)) { + if (!\is_string($type)) { + if (!(\is_string($type) || \is_object($type) && \method_exists($type, '__toString') || (\is_bool($type) || \is_numeric($type)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($type) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (string) $type; + } + } + } + if (!\is_null($style)) { + if (!\is_string($style)) { + if (!(\is_string($style) || \is_object($style) && \method_exists($style, '__toString') || (\is_bool($style) || \is_numeric($style)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($style) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($style) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $style = (string) $style; + } + } + } + if (!\is_string($prefix)) { + if (!(\is_string($prefix) || \is_object($prefix) && \method_exists($prefix, '__toString') || (\is_bool($prefix) || \is_numeric($prefix)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($prefix) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($prefix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $prefix = (string) $prefix; + } + } + if (!\is_bool($padding)) { + if (!(\is_bool($padding) || \is_numeric($padding) || \is_string($padding))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($padding) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($padding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $padding = (bool) $padding; + } + } + if (!\is_bool($escape)) { + if (!(\is_bool($escape) || \is_numeric($escape) || \is_string($escape))) { + throw new \TypeError(__METHOD__ . '(): Argument #6 ($escape) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($escape) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $escape = (bool) $escape; + } + } + $indentLength = 0; + $prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix)); + $lines = []; + if (null !== $type) { + $type = \sprintf('[%s] ', $type); + $indentLength = \strlen($type); + $lineIndentation = \str_repeat(' ', $indentLength); + } + // wrap and add newlines for each element + foreach ($messages as $key => $message) { + if ($escape) { + $message = OutputFormatter::escape($message); + } + $decorationLength = Helper::width($message) - Helper::width(Helper::removeDecoration($this->getFormatter(), $message)); + $messageLineLength = \min($this->lineLength - $prefixLength - $indentLength + $decorationLength, $this->lineLength); + $messageLines = \explode(\PHP_EOL, \wordwrap($message, $messageLineLength, \PHP_EOL, \true)); + foreach ($messageLines as $messageLine) { + $lines[] = $messageLine; + } + if (\count($messages) > 1 && $key < \count($messages) - 1) { + $lines[] = ''; + } + } + $firstLineIndex = 0; + if ($padding && $this->isDecorated()) { + $firstLineIndex = 1; + \array_unshift($lines, ''); + $lines[] = ''; + } + foreach ($lines as $i => &$line) { + if (null !== $type) { + $line = $firstLineIndex === $i ? $type . $line : $lineIndentation . $line; + } + $line = $prefix . $line; + $line .= \str_repeat(' ', \max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0)); + if ($style) { + $line = \sprintf('<%s>%s', $style, $line); + } + } + $phabelReturn = $lines; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Terminal.php b/vendor-bundle/symfony/console/Terminal.php new file mode 100644 index 000000000..ed0ef2329 --- /dev/null +++ b/vendor-bundle/symfony/console/Terminal.php @@ -0,0 +1,211 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console; + +class Terminal +{ + private static $width; + private static $height; + private static $stty; + /** + * Gets the terminal width. + * + * @return int + */ + public function getWidth() + { + $width = \getenv('COLUMNS'); + if (\false !== $width) { + return (int) \trim($width); + } + if (null === self::$width) { + self::initDimensions(); + } + return self::$width ?: 80; + } + /** + * Gets the terminal height. + * + * @return int + */ + public function getHeight() + { + $height = \getenv('LINES'); + if (\false !== $height) { + return (int) \trim($height); + } + if (null === self::$height) { + self::initDimensions(); + } + return self::$height ?: 50; + } + /** + * @internal + * + * @return bool + */ + public static function hasSttyAvailable() + { + if (null !== self::$stty) { + return self::$stty; + } + // skip check if exec function is disabled + if (!\function_exists('exec')) { + return \false; + } + \exec('stty 2>&1', $output, $exitcode); + return self::$stty = 0 === $exitcode; + } + private static function initDimensions() + { + if ('\\' === \DIRECTORY_SEPARATOR) { + if (\preg_match('/^(\\d+)x(\\d+)(?: \\((\\d+)x(\\d+)\\))?$/', \trim(\getenv('ANSICON')), $matches)) { + // extract [w, H] from "wxh (WxH)" + // or [w, h] from "wxh" + self::$width = (int) $matches[1]; + self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2]; + } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) { + // only use stty on Windows if the terminal does not support vt100 (e.g. Windows 7 + git-bash) + // testing for stty in a Windows 10 vt100-enabled console will implicitly disable vt100 support on STDOUT + self::initDimensionsUsingStty(); + } elseif (null !== ($dimensions = self::getConsoleMode())) { + // extract [w, h] from "wxh" + self::$width = (int) $dimensions[0]; + self::$height = (int) $dimensions[1]; + } + } else { + self::initDimensionsUsingStty(); + } + } + /** + * Returns whether STDOUT has vt100 support (some Windows 10+ configurations). + */ + private static function hasVt100Support() + { + $phabelReturn = \function_exists('sapi_windows_vt100_support') && \sapi_windows_vt100_support(\fopen('php://stdout', 'w')); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Initializes dimensions using the output of an stty columns line. + */ + private static function initDimensionsUsingStty() + { + if ($sttyString = self::getSttyColumns()) { + if (\preg_match('/rows.(\\d+);.columns.(\\d+);/i', $sttyString, $matches)) { + // extract [w, h] from "rows h; columns w;" + self::$width = (int) $matches[2]; + self::$height = (int) $matches[1]; + } elseif (\preg_match('/;.(\\d+).rows;.(\\d+).columns/i', $sttyString, $matches)) { + // extract [w, h] from "; h rows; w columns" + self::$width = (int) $matches[2]; + self::$height = (int) $matches[1]; + } + } + } + /** + * Runs and parses mode CON if it's available, suppressing any error output. + * + * @return int[]|null An array composed of the width and the height or null if it could not be parsed + */ + private static function getConsoleMode() + { + $info = self::readFromProcess('mode CON'); + if (null === $info || !\preg_match('/--------+\\r?\\n.+?(\\d+)\\r?\\n.+?(\\d+)\\r?\\n/', $info, $matches)) { + $phabelReturn = null; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = [(int) $matches[2], (int) $matches[1]]; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Runs and parses stty -a if it's available, suppressing any error output. + */ + private static function getSttyColumns() + { + $phabelReturn = self::readFromProcess('stty -a | grep columns'); + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } + private static function readFromProcess($command) + { + if (!\is_string($command)) { + if (!(\is_string($command) || \is_object($command) && \method_exists($command, '__toString') || (\is_bool($command) || \is_numeric($command)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($command) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($command) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $command = (string) $command; + } + } + if (!\function_exists('proc_open')) { + $phabelReturn = null; + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } + $descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; + $process = \proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => \true]); + if (!\is_resource($process)) { + $phabelReturn = null; + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } + $info = \stream_get_contents($pipes[1]); + \fclose($pipes[1]); + \fclose($pipes[2]); + \proc_close($process); + $phabelReturn = $info; + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/console/Tester/ApplicationTester.php b/vendor-bundle/symfony/console/Tester/ApplicationTester.php new file mode 100644 index 000000000..aeca715d4 --- /dev/null +++ b/vendor-bundle/symfony/console/Tester/ApplicationTester.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Tester; + +use Phabel\Symfony\Component\Console\Application; +use Phabel\Symfony\Component\Console\Input\ArrayInput; +/** + * Eases the testing of console applications. + * + * When testing an application, don't forget to disable the auto exit flag: + * + * $application = new Application(); + * $application->setAutoExit(false); + * + * @author Fabien Potencier + */ +class ApplicationTester +{ + use TesterTrait; + private $application; + private $input; + private $statusCode; + public function __construct(Application $application) + { + $this->application = $application; + } + /** + * Executes the application. + * + * Available options: + * + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * * capture_stderr_separately: Make output of stdOut and stdErr separately available + * + * @return int The command exit code + */ + public function run(array $input, array $options = []) + { + $this->input = new ArrayInput($input); + if (isset($options['interactive'])) { + $this->input->setInteractive($options['interactive']); + } + if ($this->inputs) { + $this->input->setStream(self::createStream($this->inputs)); + } + $this->initOutput($options); + return $this->statusCode = $this->application->run($this->input, $this->output); + } +} diff --git a/vendor-bundle/symfony/console/Tester/CommandTester.php b/vendor-bundle/symfony/console/Tester/CommandTester.php new file mode 100644 index 000000000..c42a98539 --- /dev/null +++ b/vendor-bundle/symfony/console/Tester/CommandTester.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Tester; + +use Phabel\Symfony\Component\Console\Command\Command; +use Phabel\Symfony\Component\Console\Input\ArrayInput; +/** + * Eases the testing of console commands. + * + * @author Fabien Potencier + * @author Robin Chalas + */ +class CommandTester +{ + use TesterTrait; + private $command; + private $input; + private $statusCode; + public function __construct(Command $command) + { + $this->command = $command; + } + /** + * Executes the command. + * + * Available execution options: + * + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * * capture_stderr_separately: Make output of stdOut and stdErr separately available + * + * @param array $input An array of command arguments and options + * @param array $options An array of execution options + * + * @return int The command exit code + */ + public function execute(array $input, array $options = []) + { + // set the command name automatically if the application requires + // this argument and no command name was passed + if (!isset($input['command']) && null !== ($application = $this->command->getApplication()) && $application->getDefinition()->hasArgument('command')) { + $input = \array_merge(['command' => $this->command->getName()], $input); + } + $this->input = new ArrayInput($input); + // Use an in-memory input stream even if no inputs are set so that QuestionHelper::ask() does not rely on the blocking STDIN. + $this->input->setStream(self::createStream($this->inputs)); + if (isset($options['interactive'])) { + $this->input->setInteractive($options['interactive']); + } + if (!isset($options['decorated'])) { + $options['decorated'] = \false; + } + $this->initOutput($options); + return $this->statusCode = $this->command->run($this->input, $this->output); + } +} diff --git a/vendor-bundle/symfony/console/Tester/TesterTrait.php b/vendor-bundle/symfony/console/Tester/TesterTrait.php new file mode 100644 index 000000000..b3ef2e098 --- /dev/null +++ b/vendor-bundle/symfony/console/Tester/TesterTrait.php @@ -0,0 +1,171 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Console\Tester; + +use Phabel\Symfony\Component\Console\Input\InputInterface; +use Phabel\Symfony\Component\Console\Output\ConsoleOutput; +use Phabel\Symfony\Component\Console\Output\OutputInterface; +use Phabel\Symfony\Component\Console\Output\StreamOutput; +/** + * @author Amrouche Hamza + */ +trait TesterTrait +{ + /** @var StreamOutput */ + private $output; + private $inputs = []; + private $captureStreamsIndependently = \false; + /** + * Gets the display returned by the last execution of the command or application. + * + * @throws \RuntimeException If it's called before the execute method + * + * @return string The display + */ + public function getDisplay($normalize = \false) + { + if (!\is_bool($normalize)) { + if (!(\is_bool($normalize) || \is_numeric($normalize) || \is_string($normalize))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($normalize) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($normalize) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $normalize = (bool) $normalize; + } + } + if (null === $this->output) { + throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?'); + } + \rewind($this->output->getStream()); + $display = \stream_get_contents($this->output->getStream()); + if ($normalize) { + $display = \str_replace(\PHP_EOL, "\n", $display); + } + return $display; + } + /** + * Gets the output written to STDERR by the application. + * + * @param bool $normalize Whether to normalize end of lines to \n or not + * + * @return string + */ + public function getErrorOutput($normalize = \false) + { + if (!\is_bool($normalize)) { + if (!(\is_bool($normalize) || \is_numeric($normalize) || \is_string($normalize))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($normalize) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($normalize) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $normalize = (bool) $normalize; + } + } + if (!$this->captureStreamsIndependently) { + throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.'); + } + \rewind($this->output->getErrorOutput()->getStream()); + $display = \stream_get_contents($this->output->getErrorOutput()->getStream()); + if ($normalize) { + $display = \str_replace(\PHP_EOL, "\n", $display); + } + return $display; + } + /** + * Gets the input instance used by the last execution of the command or application. + * + * @return InputInterface The current input instance + */ + public function getInput() + { + return $this->input; + } + /** + * Gets the output instance used by the last execution of the command or application. + * + * @return OutputInterface The current output instance + */ + public function getOutput() + { + return $this->output; + } + /** + * Gets the status code returned by the last execution of the command or application. + * + * @throws \RuntimeException If it's called before the execute method + * + * @return int The status code + */ + public function getStatusCode() + { + if (null === $this->statusCode) { + throw new \RuntimeException('Status code not initialized, did you execute the command before requesting the status code?'); + } + return $this->statusCode; + } + /** + * Sets the user inputs. + * + * @param array $inputs An array of strings representing each input + * passed to the command input stream + * + * @return $this + */ + public function setInputs(array $inputs) + { + $this->inputs = $inputs; + return $this; + } + /** + * Initializes the output property. + * + * Available options: + * + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * * capture_stderr_separately: Make output of stdOut and stdErr separately available + */ + private function initOutput(array $options) + { + $this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately']; + if (!$this->captureStreamsIndependently) { + $this->output = new StreamOutput(\fopen('php://memory', 'w', \false)); + if (isset($options['decorated'])) { + $this->output->setDecorated($options['decorated']); + } + if (isset($options['verbosity'])) { + $this->output->setVerbosity($options['verbosity']); + } + } else { + $this->output = new ConsoleOutput(isset($options['verbosity']) ? $options['verbosity'] : ConsoleOutput::VERBOSITY_NORMAL, isset($options['decorated']) ? $options['decorated'] : null); + $errorOutput = new StreamOutput(\fopen('php://memory', 'w', \false)); + $errorOutput->setFormatter($this->output->getFormatter()); + $errorOutput->setVerbosity($this->output->getVerbosity()); + $errorOutput->setDecorated($this->output->isDecorated()); + $reflectedOutput = new \ReflectionObject($this->output); + $strErrProperty = $reflectedOutput->getProperty('stderr'); + $strErrProperty->setAccessible(\true); + $strErrProperty->setValue($this->output, $errorOutput); + $reflectedParent = $reflectedOutput->getParentClass(); + $streamProperty = $reflectedParent->getProperty('stream'); + $streamProperty->setAccessible(\true); + $streamProperty->setValue($this->output, \fopen('php://memory', 'w', \false)); + } + } + /** + * @return resource + */ + private static function createStream(array $inputs) + { + $stream = \fopen('php://memory', 'r+', \false); + foreach ($inputs as $input) { + \fwrite($stream, $input . \PHP_EOL); + } + \rewind($stream); + return $stream; + } +} diff --git a/vendor-bundle/symfony/deprecation-contracts/function.php b/vendor-bundle/symfony/deprecation-contracts/function.php new file mode 100644 index 000000000..1217164c4 --- /dev/null +++ b/vendor-bundle/symfony/deprecation-contracts/function.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +if (!\function_exists('Phabel\\trigger_deprecation')) { + /** + * Triggers a silenced deprecation notice. + * + * @param string $package The name of the Composer package that is triggering the deprecation + * @param string $version The version of the package that introduced the deprecation + * @param string $message The message of the deprecation + * @param mixed ...$args Values to insert in the message using printf() formatting + * + * @author Nicolas Grekas + */ + function trigger_deprecation($package, $version, $message, ...$args) + { + if (!\is_string($package)) { + if (!(\is_string($package) || \is_object($package) && \method_exists($package, '__toString') || (\is_bool($package) || \is_numeric($package)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($package) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($package) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $package = (string) $package; + } + } + if (!\is_string($version)) { + if (!(\is_string($version) || \is_object($version) && \method_exists($version, '__toString') || (\is_bool($version) || \is_numeric($version)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($version) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($version) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $version = (string) $version; + } + } + if (!\is_string($message)) { + if (!(\is_string($message) || \is_object($message) && \method_exists($message, '__toString') || (\is_bool($message) || \is_numeric($message)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($message) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($message) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $message = (string) $message; + } + } + @\trigger_error(($package || $version ? "Since {$package} {$version}: " : '') . ($args ? \vsprintf($message, $args) : $message), \E_USER_DEPRECATED); + } +} diff --git a/vendor-bundle/symfony/polyfill-ctype/Ctype.php b/vendor-bundle/symfony/polyfill-ctype/Ctype.php new file mode 100644 index 000000000..a7f186d9b --- /dev/null +++ b/vendor-bundle/symfony/polyfill-ctype/Ctype.php @@ -0,0 +1,201 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Polyfill\Ctype; + +/** + * Ctype implementation through regex. + * + * @internal + * + * @author Gert de Pagter + */ +final class Ctype +{ + /** + * Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise. + * + * @see https://php.net/ctype-alnum + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_alnum($text) + { + $text = self::convert_int_to_char_for_ctype($text); + return \is_string($text) && '' !== $text && !\preg_match('/[^A-Za-z0-9]/', $text); + } + /** + * Returns TRUE if every character in text is a letter, FALSE otherwise. + * + * @see https://php.net/ctype-alpha + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_alpha($text) + { + $text = self::convert_int_to_char_for_ctype($text); + return \is_string($text) && '' !== $text && !\preg_match('/[^A-Za-z]/', $text); + } + /** + * Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise. + * + * @see https://php.net/ctype-cntrl + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_cntrl($text) + { + $text = self::convert_int_to_char_for_ctype($text); + return \is_string($text) && '' !== $text && !\preg_match('/[^\\x00-\\x1f\\x7f]/', $text); + } + /** + * Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise. + * + * @see https://php.net/ctype-digit + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_digit($text) + { + $text = self::convert_int_to_char_for_ctype($text); + return \is_string($text) && '' !== $text && !\preg_match('/[^0-9]/', $text); + } + /** + * Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise. + * + * @see https://php.net/ctype-graph + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_graph($text) + { + $text = self::convert_int_to_char_for_ctype($text); + return \is_string($text) && '' !== $text && !\preg_match('/[^!-~]/', $text); + } + /** + * Returns TRUE if every character in text is a lowercase letter. + * + * @see https://php.net/ctype-lower + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_lower($text) + { + $text = self::convert_int_to_char_for_ctype($text); + return \is_string($text) && '' !== $text && !\preg_match('/[^a-z]/', $text); + } + /** + * Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all. + * + * @see https://php.net/ctype-print + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_print($text) + { + $text = self::convert_int_to_char_for_ctype($text); + return \is_string($text) && '' !== $text && !\preg_match('/[^ -~]/', $text); + } + /** + * Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise. + * + * @see https://php.net/ctype-punct + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_punct($text) + { + $text = self::convert_int_to_char_for_ctype($text); + return \is_string($text) && '' !== $text && !\preg_match('/[^!-\\/\\:-@\\[-`\\{-~]/', $text); + } + /** + * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters. + * + * @see https://php.net/ctype-space + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_space($text) + { + $text = self::convert_int_to_char_for_ctype($text); + return \is_string($text) && '' !== $text && !\preg_match('/[^\\s]/', $text); + } + /** + * Returns TRUE if every character in text is an uppercase letter. + * + * @see https://php.net/ctype-upper + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_upper($text) + { + $text = self::convert_int_to_char_for_ctype($text); + return \is_string($text) && '' !== $text && !\preg_match('/[^A-Z]/', $text); + } + /** + * Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise. + * + * @see https://php.net/ctype-xdigit + * + * @param string|int $text + * + * @return bool + */ + public static function ctype_xdigit($text) + { + $text = self::convert_int_to_char_for_ctype($text); + return \is_string($text) && '' !== $text && !\preg_match('/[^A-Fa-f0-9]/', $text); + } + /** + * Converts integers to their char versions according to normal ctype behaviour, if needed. + * + * If an integer between -128 and 255 inclusive is provided, + * it is interpreted as the ASCII value of a single character + * (negative values have 256 added in order to allow characters in the Extended ASCII range). + * Any other integer is interpreted as a string containing the decimal digits of the integer. + * + * @param string|int $int + * + * @return mixed + */ + private static function convert_int_to_char_for_ctype($int) + { + if (!\is_int($int)) { + return $int; + } + if ($int < -128 || $int > 255) { + return (string) $int; + } + if ($int < 0) { + $int += 256; + } + return \chr($int); + } +} diff --git a/vendor-bundle/symfony/polyfill-ctype/bootstrap.php b/vendor-bundle/symfony/polyfill-ctype/bootstrap.php new file mode 100644 index 000000000..5ddde2304 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-ctype/bootstrap.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Phabel\Symfony\Polyfill\Ctype as p; +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__ . '/bootstrap80.php'; +} +if (!\function_exists('ctype_alnum')) { + function ctype_alnum($text) + { + return p\Ctype::ctype_alnum($text); + } +} +if (!\function_exists('ctype_alpha')) { + function ctype_alpha($text) + { + return p\Ctype::ctype_alpha($text); + } +} +if (!\function_exists('ctype_cntrl')) { + function ctype_cntrl($text) + { + return p\Ctype::ctype_cntrl($text); + } +} +if (!\function_exists('ctype_digit')) { + function ctype_digit($text) + { + return p\Ctype::ctype_digit($text); + } +} +if (!\function_exists('ctype_graph')) { + function ctype_graph($text) + { + return p\Ctype::ctype_graph($text); + } +} +if (!\function_exists('ctype_lower')) { + function ctype_lower($text) + { + return p\Ctype::ctype_lower($text); + } +} +if (!\function_exists('ctype_print')) { + function ctype_print($text) + { + return p\Ctype::ctype_print($text); + } +} +if (!\function_exists('ctype_punct')) { + function ctype_punct($text) + { + return p\Ctype::ctype_punct($text); + } +} +if (!\function_exists('ctype_space')) { + function ctype_space($text) + { + return p\Ctype::ctype_space($text); + } +} +if (!\function_exists('ctype_upper')) { + function ctype_upper($text) + { + return p\Ctype::ctype_upper($text); + } +} +if (!\function_exists('ctype_xdigit')) { + function ctype_xdigit($text) + { + return p\Ctype::ctype_xdigit($text); + } +} diff --git a/vendor-bundle/symfony/polyfill-ctype/bootstrap80.php b/vendor-bundle/symfony/polyfill-ctype/bootstrap80.php new file mode 100644 index 000000000..de0b4c6d3 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-ctype/bootstrap80.php @@ -0,0 +1,167 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Phabel\Symfony\Polyfill\Ctype as p; +if (!\function_exists('ctype_alnum')) { + function ctype_alnum(mixed $text) + { + $phabelReturn = p\Ctype::ctype_alnum($text); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('ctype_alpha')) { + function ctype_alpha(mixed $text) + { + $phabelReturn = p\Ctype::ctype_alpha($text); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('ctype_cntrl')) { + function ctype_cntrl(mixed $text) + { + $phabelReturn = p\Ctype::ctype_cntrl($text); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('ctype_digit')) { + function ctype_digit(mixed $text) + { + $phabelReturn = p\Ctype::ctype_digit($text); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('ctype_graph')) { + function ctype_graph(mixed $text) + { + $phabelReturn = p\Ctype::ctype_graph($text); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('ctype_lower')) { + function ctype_lower(mixed $text) + { + $phabelReturn = p\Ctype::ctype_lower($text); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('ctype_print')) { + function ctype_print(mixed $text) + { + $phabelReturn = p\Ctype::ctype_print($text); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('ctype_punct')) { + function ctype_punct(mixed $text) + { + $phabelReturn = p\Ctype::ctype_punct($text); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('ctype_space')) { + function ctype_space(mixed $text) + { + $phabelReturn = p\Ctype::ctype_space($text); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('ctype_upper')) { + function ctype_upper(mixed $text) + { + $phabelReturn = p\Ctype::ctype_upper($text); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('ctype_xdigit')) { + function ctype_xdigit(mixed $text) + { + $phabelReturn = p\Ctype::ctype_xdigit($text); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/polyfill-intl-grapheme/Grapheme.php b/vendor-bundle/symfony/polyfill-intl-grapheme/Grapheme.php new file mode 100644 index 000000000..6137921ed --- /dev/null +++ b/vendor-bundle/symfony/polyfill-intl-grapheme/Grapheme.php @@ -0,0 +1,210 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Polyfill\Intl\Grapheme; + +\define('SYMFONY_GRAPHEME_CLUSTER_RX', \PCRE_VERSION >= '8.32' ? '\\X' : Grapheme::GRAPHEME_CLUSTER_RX); +/** + * Partial intl implementation in pure PHP. + * + * Implemented: + * - grapheme_extract - Extract a sequence of grapheme clusters from a text buffer, which must be encoded in UTF-8 + * - grapheme_stripos - Find position (in grapheme units) of first occurrence of a case-insensitive string + * - grapheme_stristr - Returns part of haystack string from the first occurrence of case-insensitive needle to the end of haystack + * - grapheme_strlen - Get string length in grapheme units + * - grapheme_strpos - Find position (in grapheme units) of first occurrence of a string + * - grapheme_strripos - Find position (in grapheme units) of last occurrence of a case-insensitive string + * - grapheme_strrpos - Find position (in grapheme units) of last occurrence of a string + * - grapheme_strstr - Returns part of haystack string from the first occurrence of needle to the end of haystack + * - grapheme_substr - Return part of a string + * + * @author Nicolas Grekas + * + * @internal + */ +final class Grapheme +{ + // (CRLF|([ZWNJ-ZWJ]|T+|L*(LV?V+|LV|LVT)T*|L+|[^Control])[Extend]*|[Control]) + // This regular expression is a work around for http://bugs.exim.org/1279 + const GRAPHEME_CLUSTER_RX = '(?:\\r\\n|(?:[ -~\\x{200C}\\x{200D}]|[ᆨ-ᇹ]+|[ᄀ-ᅟ]*(?:[가개갸걔거게겨계고과괘괴교구궈궤귀규그긔기까깨꺄꺠꺼께껴꼐꼬꽈꽤꾀꾜꾸꿔꿰뀌뀨끄끠끼나내냐냬너네녀녜노놔놰뇌뇨누눠눼뉘뉴느늬니다대댜댸더데뎌뎨도돠돼되됴두둬뒈뒤듀드듸디따때땨떄떠떼뗘뗴또똬뙈뙤뚀뚜뚸뛔뛰뜌뜨띄띠라래랴럐러레려례로롸뢔뢰료루뤄뤠뤼류르릐리마매먀먜머메며몌모뫄뫠뫼묘무뭐뭬뮈뮤므믜미바배뱌뱨버베벼볘보봐봬뵈뵤부붜붸뷔뷰브븨비빠빼뺘뺴뻐뻬뼈뼤뽀뽜뽸뾔뾰뿌뿨쀄쀠쀼쁘쁴삐사새샤섀서세셔셰소솨쇄쇠쇼수숴쉐쉬슈스싀시싸쌔쌰썌써쎄쎠쎼쏘쏴쐐쐬쑈쑤쒀쒜쒸쓔쓰씌씨아애야얘어에여예오와왜외요우워웨위유으의이자재쟈쟤저제져졔조좌좨죄죠주줘줴쥐쥬즈즤지짜째쨔쨰쩌쩨쪄쪠쪼쫘쫴쬐쬬쭈쭤쮀쮜쮸쯔쯰찌차채챠챼처체쳐쳬초촤쵀최쵸추춰췌취츄츠츼치카캐캬컈커케켜켸코콰쾌쾨쿄쿠쿼퀘퀴큐크킈키타태탸턔터테텨톄토톼퇘퇴툐투퉈퉤튀튜트틔티파패퍄퍠퍼페펴폐포퐈퐤푀표푸풔풰퓌퓨프픠피하해햐햬허헤혀혜호화홰회효후훠훼휘휴흐희히]?[ᅠ-ᆢ]+|[가-힣])[ᆨ-ᇹ]*|[ᄀ-ᅟ]+|[^\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}])[\\p{Mn}\\p{Me}\\x{09BE}\\x{09D7}\\x{0B3E}\\x{0B57}\\x{0BBE}\\x{0BD7}\\x{0CC2}\\x{0CD5}\\x{0CD6}\\x{0D3E}\\x{0D57}\\x{0DCF}\\x{0DDF}\\x{200C}\\x{200D}\\x{1D165}\\x{1D16E}-\\x{1D172}]*|[\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}])'; + const CASE_FOLD = [['µ', 'ſ', "ͅ", 'ς', "ϐ", "ϑ", "ϕ", "ϖ", "ϰ", "ϱ", "ϵ", "ẛ", "ι"], ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "ṡ", 'ι']]; + public static function grapheme_extract($s, $size, $type = \GRAPHEME_EXTR_COUNT, $start = 0, &$next = 0) + { + if (0 > $start) { + $start = \strlen($s) + $start; + } + if (!\is_scalar($s)) { + $hasError = \false; + \set_error_handler(function () use(&$hasError) { + $hasError = \true; + }); + $next = \substr($s, $start); + \restore_error_handler(); + if ($hasError) { + \substr($s, $start); + $s = ''; + } else { + $s = $next; + } + } else { + $s = \substr($s, $start); + } + $size = (int) $size; + $type = (int) $type; + $start = (int) $start; + if (\GRAPHEME_EXTR_COUNT !== $type && \GRAPHEME_EXTR_MAXBYTES !== $type && \GRAPHEME_EXTR_MAXCHARS !== $type) { + if (80000 > \PHP_VERSION_ID) { + return \false; + } + throw new \ValueError('grapheme_extract(): Argument #3 ($type) must be one of GRAPHEME_EXTR_COUNT, GRAPHEME_EXTR_MAXBYTES, or GRAPHEME_EXTR_MAXCHARS'); + } + if (!isset($s[0]) || 0 > $size || 0 > $start) { + return \false; + } + if (0 === $size) { + return ''; + } + $next = $start; + $s = \preg_split('/(' . SYMFONY_GRAPHEME_CLUSTER_RX . ')/u', "\r\n" . $s, $size + 1, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE); + if (!isset($s[1])) { + return \false; + } + $i = 1; + $ret = ''; + do { + if (\GRAPHEME_EXTR_COUNT === $type) { + --$size; + } elseif (\GRAPHEME_EXTR_MAXBYTES === $type) { + $size -= \strlen($s[$i]); + } else { + $size -= \iconv_strlen($s[$i], 'UTF-8//IGNORE'); + } + if ($size >= 0) { + $ret .= $s[$i]; + } + } while (isset($s[++$i]) && $size > 0); + $next += \strlen($ret); + return $ret; + } + public static function grapheme_strlen($s) + { + \preg_replace('/' . SYMFONY_GRAPHEME_CLUSTER_RX . '/u', '', $s, -1, $len); + return 0 === $len && '' !== $s ? null : $len; + } + public static function grapheme_substr($s, $start, $len = null) + { + if (null === $len) { + $len = 2147483647; + } + \preg_match_all('/' . SYMFONY_GRAPHEME_CLUSTER_RX . '/u', $s, $s); + $slen = \count($s[0]); + $start = (int) $start; + if (0 > $start) { + $start += $slen; + } + if (0 > $start) { + if (\PHP_VERSION_ID < 80000) { + return \false; + } + $start = 0; + } + if ($start >= $slen) { + return \PHP_VERSION_ID >= 80000 ? '' : \false; + } + $rem = $slen - $start; + if (0 > $len) { + $len += $rem; + } + if (0 === $len) { + return ''; + } + if (0 > $len) { + return \PHP_VERSION_ID >= 80000 ? '' : \false; + } + if ($len > $rem) { + $len = $rem; + } + return \implode('', \array_slice($s[0], $start, $len)); + } + public static function grapheme_strpos($s, $needle, $offset = 0) + { + return self::grapheme_position($s, $needle, $offset, 0); + } + public static function grapheme_stripos($s, $needle, $offset = 0) + { + return self::grapheme_position($s, $needle, $offset, 1); + } + public static function grapheme_strrpos($s, $needle, $offset = 0) + { + return self::grapheme_position($s, $needle, $offset, 2); + } + public static function grapheme_strripos($s, $needle, $offset = 0) + { + return self::grapheme_position($s, $needle, $offset, 3); + } + public static function grapheme_stristr($s, $needle, $beforeNeedle = \false) + { + return \mb_stristr($s, $needle, $beforeNeedle, 'UTF-8'); + } + public static function grapheme_strstr($s, $needle, $beforeNeedle = \false) + { + return \mb_strstr($s, $needle, $beforeNeedle, 'UTF-8'); + } + private static function grapheme_position($s, $needle, $offset, $mode) + { + $needle = (string) $needle; + if (80000 > \PHP_VERSION_ID && !\preg_match('/./us', $needle)) { + return \false; + } + $s = (string) $s; + if (!\preg_match('/./us', $s)) { + return \false; + } + if ($offset > 0) { + $s = self::grapheme_substr($s, $offset); + } elseif ($offset < 0) { + if (2 > $mode) { + $offset += self::grapheme_strlen($s); + $s = self::grapheme_substr($s, $offset); + if (0 > $offset) { + $offset = 0; + } + } elseif (0 > ($offset += self::grapheme_strlen($needle))) { + $s = self::grapheme_substr($s, 0, $offset); + $offset = 0; + } else { + $offset = 0; + } + } + // As UTF-8 is self-synchronizing, and we have ensured the strings are valid UTF-8, + // we can use normal binary string functions here. For case-insensitive searches, + // case fold the strings first. + $caseInsensitive = $mode & 1; + $reverse = $mode & 2; + if ($caseInsensitive) { + // Use the same case folding mode as mbstring does for mb_stripos(). + // Stick to SIMPLE case folding to avoid changing the length of the string, which + // might result in offsets being shifted. + $mode = \defined('MB_CASE_FOLD_SIMPLE') ? \MB_CASE_FOLD_SIMPLE : \MB_CASE_LOWER; + $s = \mb_convert_case($s, $mode, 'UTF-8'); + $needle = \mb_convert_case($needle, $mode, 'UTF-8'); + if (!\defined('MB_CASE_FOLD_SIMPLE')) { + $s = \str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); + $needle = \str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $needle); + } + } + if ($reverse) { + $needlePos = \strrpos($s, $needle); + } else { + $needlePos = \strpos($s, $needle); + } + return \false !== $needlePos ? self::grapheme_strlen(\substr($s, 0, $needlePos)) + $offset : \false; + } +} diff --git a/vendor-bundle/symfony/polyfill-intl-grapheme/bootstrap.php b/vendor-bundle/symfony/polyfill-intl-grapheme/bootstrap.php new file mode 100644 index 000000000..3a8323f62 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-intl-grapheme/bootstrap.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Phabel\Symfony\Polyfill\Intl\Grapheme as p; +if (\extension_loaded('intl')) { + return; +} +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__ . '/bootstrap80.php'; +} +if (!\defined('GRAPHEME_EXTR_COUNT')) { + \define('GRAPHEME_EXTR_COUNT', 0); +} +if (!\defined('GRAPHEME_EXTR_MAXBYTES')) { + \define('GRAPHEME_EXTR_MAXBYTES', 1); +} +if (!\defined('GRAPHEME_EXTR_MAXCHARS')) { + \define('GRAPHEME_EXTR_MAXCHARS', 2); +} +if (!\function_exists('grapheme_extract')) { + function grapheme_extract($haystack, $size, $type = 0, $start = 0, &$next = 0) + { + return p\Grapheme::grapheme_extract($haystack, $size, $type, $start, $next); + } +} +if (!\function_exists('grapheme_stripos')) { + function grapheme_stripos($haystack, $needle, $offset = 0) + { + return p\Grapheme::grapheme_stripos($haystack, $needle, $offset); + } +} +if (!\function_exists('grapheme_stristr')) { + function grapheme_stristr($haystack, $needle, $beforeNeedle = \false) + { + return p\Grapheme::grapheme_stristr($haystack, $needle, $beforeNeedle); + } +} +if (!\function_exists('grapheme_strlen')) { + function grapheme_strlen($input) + { + return p\Grapheme::grapheme_strlen($input); + } +} +if (!\function_exists('grapheme_strpos')) { + function grapheme_strpos($haystack, $needle, $offset = 0) + { + return p\Grapheme::grapheme_strpos($haystack, $needle, $offset); + } +} +if (!\function_exists('grapheme_strripos')) { + function grapheme_strripos($haystack, $needle, $offset = 0) + { + return p\Grapheme::grapheme_strripos($haystack, $needle, $offset); + } +} +if (!\function_exists('grapheme_strrpos')) { + function grapheme_strrpos($haystack, $needle, $offset = 0) + { + return p\Grapheme::grapheme_strrpos($haystack, $needle, $offset); + } +} +if (!\function_exists('grapheme_strstr')) { + function grapheme_strstr($haystack, $needle, $beforeNeedle = \false) + { + return p\Grapheme::grapheme_strstr($haystack, $needle, $beforeNeedle); + } +} +if (!\function_exists('grapheme_substr')) { + function grapheme_substr($string, $offset, $length = null) + { + return p\Grapheme::grapheme_substr($string, $offset, $length); + } +} diff --git a/vendor-bundle/symfony/polyfill-intl-grapheme/bootstrap80.php b/vendor-bundle/symfony/polyfill-intl-grapheme/bootstrap80.php new file mode 100644 index 000000000..7f7345be1 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-intl-grapheme/bootstrap80.php @@ -0,0 +1,400 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Phabel\Symfony\Polyfill\Intl\Grapheme as p; +if (!\defined('GRAPHEME_EXTR_COUNT')) { + \define('GRAPHEME_EXTR_COUNT', 0); +} +if (!\defined('GRAPHEME_EXTR_MAXBYTES')) { + \define('GRAPHEME_EXTR_MAXBYTES', 1); +} +if (!\defined('GRAPHEME_EXTR_MAXCHARS')) { + \define('GRAPHEME_EXTR_MAXCHARS', 2); +} +if (!\function_exists('grapheme_extract')) { + function grapheme_extract($haystack, $size, $type = \GRAPHEME_EXTR_COUNT, $offset = 0, &$next = null) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($size)) { + if (!\is_int($size)) { + if (!(\is_bool($size) || \is_numeric($size))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($size) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($size) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $size = (int) $size; + } + } + } + if (!\is_null($type)) { + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($type) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + } + if (!\is_null($offset)) { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($offset) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + } + $phabelReturn = p\Grapheme::grapheme_extract((string) $haystack, (int) $size, (int) $type, (int) $offset, $next); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('grapheme_stripos')) { + function grapheme_stripos($haystack, $needle, $offset = 0) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($offset)) { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + } + $phabelReturn = p\Grapheme::grapheme_stripos((string) $haystack, (string) $needle, (int) $offset); + if (!$phabelReturn instanceof false) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('grapheme_stristr')) { + function grapheme_stristr($haystack, $needle, $beforeNeedle = \false) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($beforeNeedle)) { + if (!\is_bool($beforeNeedle)) { + if (!(\is_bool($beforeNeedle) || \is_numeric($beforeNeedle) || \is_string($beforeNeedle))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($beforeNeedle) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($beforeNeedle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $beforeNeedle = (bool) $beforeNeedle; + } + } + } + $phabelReturn = p\Grapheme::grapheme_stristr((string) $haystack, (string) $needle, (bool) $beforeNeedle); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('grapheme_strlen')) { + function grapheme_strlen($string) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + $phabelReturn = p\Grapheme::grapheme_strlen((string) $string); + if (!($phabelReturn instanceof false || \is_null($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|int|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('grapheme_strpos')) { + function grapheme_strpos($haystack, $needle, $offset = 0) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($offset)) { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + } + $phabelReturn = p\Grapheme::grapheme_strpos((string) $haystack, (string) $needle, (int) $offset); + if (!$phabelReturn instanceof false) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('grapheme_strripos')) { + function grapheme_strripos($haystack, $needle, $offset = 0) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($offset)) { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + } + $phabelReturn = p\Grapheme::grapheme_strripos((string) $haystack, (string) $needle, (int) $offset); + if (!$phabelReturn instanceof false) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('grapheme_strrpos')) { + function grapheme_strrpos($haystack, $needle, $offset = 0) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($offset)) { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + } + $phabelReturn = p\Grapheme::grapheme_strrpos((string) $haystack, (string) $needle, (int) $offset); + if (!$phabelReturn instanceof false) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('grapheme_strstr')) { + function grapheme_strstr($haystack, $needle, $beforeNeedle = \false) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($beforeNeedle)) { + if (!\is_bool($beforeNeedle)) { + if (!(\is_bool($beforeNeedle) || \is_numeric($beforeNeedle) || \is_string($beforeNeedle))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($beforeNeedle) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($beforeNeedle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $beforeNeedle = (bool) $beforeNeedle; + } + } + } + $phabelReturn = p\Grapheme::grapheme_strstr((string) $haystack, (string) $needle, (bool) $beforeNeedle); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('grapheme_substr')) { + function grapheme_substr($string, $offset, $length = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($offset)) { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + } + $phabelReturn = p\Grapheme::grapheme_substr((string) $string, (int) $offset, $length); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/polyfill-intl-normalizer/Normalizer.php b/vendor-bundle/symfony/polyfill-intl-normalizer/Normalizer.php new file mode 100644 index 000000000..75acc6398 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-intl-normalizer/Normalizer.php @@ -0,0 +1,286 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Polyfill\Intl\Normalizer; + +/** + * Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension. + * + * It has been validated with Unicode 6.3 Normalization Conformance Test. + * See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations. + * + * @author Nicolas Grekas + * + * @internal + */ +class Normalizer +{ + const FORM_D = \Normalizer::FORM_D; + const FORM_KD = \Normalizer::FORM_KD; + const FORM_C = \Normalizer::FORM_C; + const FORM_KC = \Normalizer::FORM_KC; + const NFD = \Normalizer::NFD; + const NFKD = \Normalizer::NFKD; + const NFC = \Normalizer::NFC; + const NFKC = \Normalizer::NFKC; + private static $C; + private static $D; + private static $KD; + private static $cC; + private static $ulenMask = ["\xc0" => 2, "\xd0" => 2, "\xe0" => 3, "\xf0" => 4]; + private static $ASCII = " eiasntrolud][cmp'\ng|hv.fb,:=-q10C2*yx)(L9AS/P\"EjMIk3>5T \PHP_VERSION_ID) { + return \false; + } + throw new \ValueError('normalizer_normalize(): Argument #2 ($form) must be a a valid normalization form'); + } + if ('' === $s) { + return ''; + } + if ($K && null === self::$KD) { + self::$KD = self::getData('compatibilityDecomposition'); + } + if (null === self::$D) { + self::$D = self::getData('canonicalDecomposition'); + self::$cC = self::getData('combiningClass'); + } + if (null !== ($mbEncoding = 2 & (int) \ini_get('mbstring.func_overload') ? \mb_internal_encoding() : null)) { + \mb_internal_encoding('8bit'); + } + $r = self::decompose($s, $K); + if ($C) { + if (null === self::$C) { + self::$C = self::getData('canonicalComposition'); + } + $r = self::recompose($r); + } + if (null !== $mbEncoding) { + \mb_internal_encoding($mbEncoding); + } + return $r; + } + private static function recompose($s) + { + $ASCII = self::$ASCII; + $compMap = self::$C; + $combClass = self::$cC; + $ulenMask = self::$ulenMask; + $result = $tail = ''; + $i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xf0"]; + $len = \strlen($s); + $lastUchr = \substr($s, 0, $i); + $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0; + while ($i < $len) { + if ($s[$i] < "\x80") { + // ASCII chars + if ($tail) { + $lastUchr .= $tail; + $tail = ''; + } + if ($j = \strspn($s, $ASCII, $i + 1)) { + $lastUchr .= \substr($s, $i, $j); + $i += $j; + } + $result .= $lastUchr; + $lastUchr = $s[$i]; + $lastUcls = 0; + ++$i; + continue; + } + $ulen = $ulenMask[$s[$i] & "\xf0"]; + $uchr = \substr($s, $i, $ulen); + if ($lastUchr < "ᄀ" || "ᄒ" < $lastUchr || $uchr < "ᅡ" || "ᅵ" < $uchr || $lastUcls) { + // Table lookup and combining chars composition + $ucls = isset($combClass[$uchr]) ? $combClass[$uchr] : 0; + if (isset($compMap[$lastUchr . $uchr]) && (!$lastUcls || $lastUcls < $ucls)) { + $lastUchr = $compMap[$lastUchr . $uchr]; + } elseif ($lastUcls = $ucls) { + $tail .= $uchr; + } else { + if ($tail) { + $lastUchr .= $tail; + $tail = ''; + } + $result .= $lastUchr; + $lastUchr = $uchr; + } + } else { + // Hangul chars + $L = \ord($lastUchr[2]) - 0x80; + $V = \ord($uchr[2]) - 0xa1; + $T = 0; + $uchr = \substr($s, $i + $ulen, 3); + if ("ᆧ" <= $uchr && $uchr <= "ᇂ") { + $T = \ord($uchr[2]) - 0xa7; + 0 > $T && ($T += 0x40); + $ulen += 3; + } + $L = 0xac00 + ($L * 21 + $V) * 28 + $T; + $lastUchr = \chr(0xe0 | $L >> 12) . \chr(0x80 | $L >> 6 & 0x3f) . \chr(0x80 | $L & 0x3f); + } + $i += $ulen; + } + return $result . $lastUchr . $tail; + } + private static function decompose($s, $c) + { + $result = ''; + $ASCII = self::$ASCII; + $decompMap = self::$D; + $combClass = self::$cC; + $ulenMask = self::$ulenMask; + if ($c) { + $compatMap = self::$KD; + } + $c = []; + $i = 0; + $len = \strlen($s); + while ($i < $len) { + if ($s[$i] < "\x80") { + // ASCII chars + if ($c) { + \ksort($c); + $result .= \implode('', $c); + $c = []; + } + $j = 1 + \strspn($s, $ASCII, $i + 1); + $result .= \substr($s, $i, $j); + $i += $j; + continue; + } + $ulen = $ulenMask[$s[$i] & "\xf0"]; + $uchr = \substr($s, $i, $ulen); + $i += $ulen; + if ($uchr < "가" || "힣" < $uchr) { + // Table lookup + if ($uchr !== ($j = isset($compatMap[$uchr]) ? $compatMap[$uchr] : (isset($decompMap[$uchr]) ? $decompMap[$uchr] : $uchr))) { + $uchr = $j; + $j = \strlen($uchr); + $ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xf0"]; + if ($ulen != $j) { + // Put trailing chars in $s + $j -= $ulen; + $i -= $j; + if (0 > $i) { + $s = \str_repeat(' ', -$i) . $s; + $len -= $i; + $i = 0; + } + while ($j--) { + $s[$i + $j] = $uchr[$ulen + $j]; + } + $uchr = \substr($uchr, 0, $ulen); + } + } + if (isset($combClass[$uchr])) { + // Combining chars, for sorting + if (!isset($c[$combClass[$uchr]])) { + $c[$combClass[$uchr]] = ''; + } + $c[$combClass[$uchr]] .= $uchr; + continue; + } + } else { + // Hangul chars + $uchr = \unpack('C*', $uchr); + $j = ($uchr[1] - 224 << 12) + ($uchr[2] - 128 << 6) + $uchr[3] - 0xac80; + $uchr = "\xe1\x84" . \chr(0x80 + (int) ($j / 588)) . "\xe1\x85" . \chr(0xa1 + (int) ($j % 588 / 28)); + if ($j %= 28) { + $uchr .= $j < 25 ? "\xe1\x86" . \chr(0xa7 + $j) : "\xe1\x87" . \chr(0x67 + $j); + } + } + if ($c) { + \ksort($c); + $result .= \implode('', $c); + $c = []; + } + $result .= $uchr; + } + if ($c) { + \ksort($c); + $result .= \implode('', $c); + } + return $result; + } + private static function getData($file) + { + if (\file_exists($file = __DIR__ . '/Resources/unidata/' . $file . '.php')) { + return require $file; + } + return \false; + } +} diff --git a/vendor-bundle/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php b/vendor-bundle/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php new file mode 100644 index 000000000..30733946f --- /dev/null +++ b/vendor-bundle/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php @@ -0,0 +1,20 @@ + 'À', 'Á' => 'Á', 'Â' => 'Â', 'Ã' => 'Ã', 'Ä' => 'Ä', 'Å' => 'Å', 'Ç' => 'Ç', 'È' => 'È', 'É' => 'É', 'Ê' => 'Ê', 'Ë' => 'Ë', 'Ì' => 'Ì', 'Í' => 'Í', 'Î' => 'Î', 'Ï' => 'Ï', 'Ñ' => 'Ñ', 'Ò' => 'Ò', 'Ó' => 'Ó', 'Ô' => 'Ô', 'Õ' => 'Õ', 'Ö' => 'Ö', 'Ù' => 'Ù', 'Ú' => 'Ú', 'Û' => 'Û', 'Ü' => 'Ü', 'Ý' => 'Ý', 'à' => 'à', 'á' => 'á', 'â' => 'â', 'ã' => 'ã', 'ä' => 'ä', 'å' => 'å', 'ç' => 'ç', 'è' => 'è', 'é' => 'é', 'ê' => 'ê', 'ë' => 'ë', 'ì' => 'ì', 'í' => 'í', 'î' => 'î', 'ï' => 'ï', 'ñ' => 'ñ', 'ò' => 'ò', 'ó' => 'ó', 'ô' => 'ô', 'õ' => 'õ', 'ö' => 'ö', 'ù' => 'ù', 'ú' => 'ú', 'û' => 'û', 'ü' => 'ü', 'ý' => 'ý', 'ÿ' => 'ÿ', 'Ā' => 'Ā', 'ā' => 'ā', 'Ă' => 'Ă', 'ă' => 'ă', 'Ą' => 'Ą', 'ą' => 'ą', 'Ć' => 'Ć', 'ć' => 'ć', 'Ĉ' => 'Ĉ', 'ĉ' => 'ĉ', 'Ċ' => 'Ċ', 'ċ' => 'ċ', 'Č' => 'Č', 'č' => 'č', 'Ď' => 'Ď', 'ď' => 'ď', 'Ē' => 'Ē', 'ē' => 'ē', 'Ĕ' => 'Ĕ', 'ĕ' => 'ĕ', 'Ė' => 'Ė', 'ė' => 'ė', 'Ę' => 'Ę', 'ę' => 'ę', 'Ě' => 'Ě', 'ě' => 'ě', 'Ĝ' => 'Ĝ', 'ĝ' => 'ĝ', 'Ğ' => 'Ğ', 'ğ' => 'ğ', 'Ġ' => 'Ġ', 'ġ' => 'ġ', 'Ģ' => 'Ģ', 'ģ' => 'ģ', 'Ĥ' => 'Ĥ', 'ĥ' => 'ĥ', 'Ĩ' => 'Ĩ', 'ĩ' => 'ĩ', 'Ī' => 'Ī', 'ī' => 'ī', 'Ĭ' => 'Ĭ', 'ĭ' => 'ĭ', 'Į' => 'Į', 'į' => 'į', 'İ' => 'İ', 'Ĵ' => 'Ĵ', 'ĵ' => 'ĵ', 'Ķ' => 'Ķ', 'ķ' => 'ķ', 'Ĺ' => 'Ĺ', 'ĺ' => 'ĺ', 'Ļ' => 'Ļ', 'ļ' => 'ļ', 'Ľ' => 'Ľ', 'ľ' => 'ľ', 'Ń' => 'Ń', 'ń' => 'ń', 'Ņ' => 'Ņ', 'ņ' => 'ņ', 'Ň' => 'Ň', 'ň' => 'ň', 'Ō' => 'Ō', 'ō' => 'ō', 'Ŏ' => 'Ŏ', 'ŏ' => 'ŏ', 'Ő' => 'Ő', 'ő' => 'ő', 'Ŕ' => 'Ŕ', 'ŕ' => 'ŕ', 'Ŗ' => 'Ŗ', 'ŗ' => 'ŗ', 'Ř' => 'Ř', 'ř' => 'ř', 'Ś' => 'Ś', 'ś' => 'ś', 'Ŝ' => 'Ŝ', 'ŝ' => 'ŝ', 'Ş' => 'Ş', 'ş' => 'ş', 'Š' => 'Š', 'š' => 'š', 'Ţ' => 'Ţ', 'ţ' => 'ţ', 'Ť' => 'Ť', 'ť' => 'ť', 'Ũ' => 'Ũ', 'ũ' => 'ũ', 'Ū' => 'Ū', 'ū' => 'ū', 'Ŭ' => 'Ŭ', 'ŭ' => 'ŭ', 'Ů' => 'Ů', 'ů' => 'ů', 'Ű' => 'Ű', 'ű' => 'ű', 'Ų' => 'Ų', 'ų' => 'ų', 'Ŵ' => 'Ŵ', 'ŵ' => 'ŵ', 'Ŷ' => 'Ŷ', 'ŷ' => 'ŷ', 'Ÿ' => 'Ÿ', 'Ź' => 'Ź', 'ź' => 'ź', 'Ż' => 'Ż', 'ż' => 'ż', 'Ž' => 'Ž', 'ž' => 'ž', 'Ơ' => 'Ơ', 'ơ' => 'ơ', 'Ư' => 'Ư', 'ư' => 'ư', 'Ǎ' => 'Ǎ', 'ǎ' => 'ǎ', 'Ǐ' => 'Ǐ', 'ǐ' => 'ǐ', 'Ǒ' => 'Ǒ', 'ǒ' => 'ǒ', 'Ǔ' => 'Ǔ', 'ǔ' => 'ǔ', 'Ǖ' => 'Ǖ', 'ǖ' => 'ǖ', 'Ǘ' => 'Ǘ', 'ǘ' => 'ǘ', 'Ǚ' => 'Ǚ', 'ǚ' => 'ǚ', 'Ǜ' => 'Ǜ', 'ǜ' => 'ǜ', 'Ǟ' => 'Ǟ', 'ǟ' => 'ǟ', 'Ǡ' => 'Ǡ', 'ǡ' => 'ǡ', 'Ǣ' => 'Ǣ', 'ǣ' => 'ǣ', 'Ǧ' => 'Ǧ', 'ǧ' => 'ǧ', 'Ǩ' => 'Ǩ', 'ǩ' => 'ǩ', 'Ǫ' => 'Ǫ', 'ǫ' => 'ǫ', 'Ǭ' => 'Ǭ', 'ǭ' => 'ǭ', 'Ǯ' => 'Ǯ', 'ǯ' => 'ǯ', 'ǰ' => 'ǰ', 'Ǵ' => 'Ǵ', 'ǵ' => 'ǵ', 'Ǹ' => 'Ǹ', 'ǹ' => 'ǹ', 'Ǻ' => 'Ǻ', 'ǻ' => 'ǻ', 'Ǽ' => 'Ǽ', 'ǽ' => 'ǽ', 'Ǿ' => 'Ǿ', 'ǿ' => 'ǿ', 'Ȁ' => 'Ȁ', 'ȁ' => 'ȁ', 'Ȃ' => 'Ȃ', 'ȃ' => 'ȃ', 'Ȅ' => 'Ȅ', 'ȅ' => 'ȅ', 'Ȇ' => 'Ȇ', 'ȇ' => 'ȇ', 'Ȉ' => 'Ȉ', 'ȉ' => 'ȉ', 'Ȋ' => 'Ȋ', 'ȋ' => 'ȋ', 'Ȍ' => 'Ȍ', 'ȍ' => 'ȍ', 'Ȏ' => 'Ȏ', 'ȏ' => 'ȏ', 'Ȑ' => 'Ȑ', 'ȑ' => 'ȑ', 'Ȓ' => 'Ȓ', 'ȓ' => 'ȓ', 'Ȕ' => 'Ȕ', 'ȕ' => 'ȕ', 'Ȗ' => 'Ȗ', 'ȗ' => 'ȗ', 'Ș' => 'Ș', 'ș' => 'ș', 'Ț' => 'Ț', 'ț' => 'ț', 'Ȟ' => 'Ȟ', 'ȟ' => 'ȟ', 'Ȧ' => 'Ȧ', 'ȧ' => 'ȧ', 'Ȩ' => 'Ȩ', 'ȩ' => 'ȩ', 'Ȫ' => 'Ȫ', 'ȫ' => 'ȫ', 'Ȭ' => 'Ȭ', 'ȭ' => 'ȭ', 'Ȯ' => 'Ȯ', 'ȯ' => 'ȯ', 'Ȱ' => 'Ȱ', 'ȱ' => 'ȱ', 'Ȳ' => 'Ȳ', 'ȳ' => 'ȳ', '΅' => '΅', 'Ά' => 'Ά', 'Έ' => 'Έ', 'Ή' => 'Ή', 'Ί' => 'Ί', 'Ό' => 'Ό', 'Ύ' => 'Ύ', 'Ώ' => 'Ώ', 'ΐ' => 'ΐ', 'Ϊ' => 'Ϊ', 'Ϋ' => 'Ϋ', 'ά' => 'ά', 'έ' => 'έ', 'ή' => 'ή', 'ί' => 'ί', 'ΰ' => 'ΰ', 'ϊ' => 'ϊ', 'ϋ' => 'ϋ', 'ό' => 'ό', 'ύ' => 'ύ', 'ώ' => 'ώ', 'ϓ' => 'ϓ', 'ϔ' => 'ϔ', 'Ѐ' => 'Ѐ', 'Ё' => 'Ё', 'Ѓ' => 'Ѓ', 'Ї' => 'Ї', 'Ќ' => 'Ќ', 'Ѝ' => 'Ѝ', 'Ў' => 'Ў', 'Й' => 'Й', 'й' => 'й', 'ѐ' => 'ѐ', 'ё' => 'ё', 'ѓ' => 'ѓ', 'ї' => 'ї', 'ќ' => 'ќ', 'ѝ' => 'ѝ', 'ў' => 'ў', 'Ѷ' => 'Ѷ', 'ѷ' => 'ѷ', 'Ӂ' => 'Ӂ', 'ӂ' => 'ӂ', 'Ӑ' => 'Ӑ', 'ӑ' => 'ӑ', 'Ӓ' => 'Ӓ', 'ӓ' => 'ӓ', 'Ӗ' => 'Ӗ', 'ӗ' => 'ӗ', 'Ӛ' => 'Ӛ', 'ӛ' => 'ӛ', 'Ӝ' => 'Ӝ', 'ӝ' => 'ӝ', 'Ӟ' => 'Ӟ', 'ӟ' => 'ӟ', 'Ӣ' => 'Ӣ', 'ӣ' => 'ӣ', 'Ӥ' => 'Ӥ', 'ӥ' => 'ӥ', 'Ӧ' => 'Ӧ', 'ӧ' => 'ӧ', 'Ӫ' => 'Ӫ', 'ӫ' => 'ӫ', 'Ӭ' => 'Ӭ', 'ӭ' => 'ӭ', 'Ӯ' => 'Ӯ', 'ӯ' => 'ӯ', 'Ӱ' => 'Ӱ', 'ӱ' => 'ӱ', 'Ӳ' => 'Ӳ', 'ӳ' => 'ӳ', 'Ӵ' => 'Ӵ', 'ӵ' => 'ӵ', 'Ӹ' => 'Ӹ', 'ӹ' => 'ӹ', 'آ' => 'آ', 'أ' => 'أ', 'ؤ' => 'ؤ', 'إ' => 'إ', 'ئ' => 'ئ', 'ۀ' => 'ۀ', 'ۂ' => 'ۂ', 'ۓ' => 'ۓ', 'ऩ' => 'ऩ', 'ऱ' => 'ऱ', 'ऴ' => 'ऴ', 'ো' => 'ো', 'ৌ' => 'ৌ', 'ୈ' => 'ୈ', 'ୋ' => 'ୋ', 'ୌ' => 'ୌ', 'ஔ' => 'ஔ', 'ொ' => 'ொ', 'ோ' => 'ோ', 'ௌ' => 'ௌ', 'ై' => 'ై', 'ೀ' => 'ೀ', 'ೇ' => 'ೇ', 'ೈ' => 'ೈ', 'ೊ' => 'ೊ', 'ೋ' => 'ೋ', 'ൊ' => 'ൊ', 'ോ' => 'ോ', 'ൌ' => 'ൌ', 'ේ' => 'ේ', 'ො' => 'ො', 'ෝ' => 'ෝ', 'ෞ' => 'ෞ', 'ဦ' => 'ဦ', 'ᬆ' => 'ᬆ', 'ᬈ' => 'ᬈ', 'ᬊ' => 'ᬊ', 'ᬌ' => 'ᬌ', 'ᬎ' => 'ᬎ', 'ᬒ' => 'ᬒ', 'ᬻ' => 'ᬻ', 'ᬽ' => 'ᬽ', 'ᭀ' => 'ᭀ', 'ᭁ' => 'ᭁ', 'ᭃ' => 'ᭃ', 'Ḁ' => 'Ḁ', 'ḁ' => 'ḁ', 'Ḃ' => 'Ḃ', 'ḃ' => 'ḃ', 'Ḅ' => 'Ḅ', 'ḅ' => 'ḅ', 'Ḇ' => 'Ḇ', 'ḇ' => 'ḇ', 'Ḉ' => 'Ḉ', 'ḉ' => 'ḉ', 'Ḋ' => 'Ḋ', 'ḋ' => 'ḋ', 'Ḍ' => 'Ḍ', 'ḍ' => 'ḍ', 'Ḏ' => 'Ḏ', 'ḏ' => 'ḏ', 'Ḑ' => 'Ḑ', 'ḑ' => 'ḑ', 'Ḓ' => 'Ḓ', 'ḓ' => 'ḓ', 'Ḕ' => 'Ḕ', 'ḕ' => 'ḕ', 'Ḗ' => 'Ḗ', 'ḗ' => 'ḗ', 'Ḙ' => 'Ḙ', 'ḙ' => 'ḙ', 'Ḛ' => 'Ḛ', 'ḛ' => 'ḛ', 'Ḝ' => 'Ḝ', 'ḝ' => 'ḝ', 'Ḟ' => 'Ḟ', 'ḟ' => 'ḟ', 'Ḡ' => 'Ḡ', 'ḡ' => 'ḡ', 'Ḣ' => 'Ḣ', 'ḣ' => 'ḣ', 'Ḥ' => 'Ḥ', 'ḥ' => 'ḥ', 'Ḧ' => 'Ḧ', 'ḧ' => 'ḧ', 'Ḩ' => 'Ḩ', 'ḩ' => 'ḩ', 'Ḫ' => 'Ḫ', 'ḫ' => 'ḫ', 'Ḭ' => 'Ḭ', 'ḭ' => 'ḭ', 'Ḯ' => 'Ḯ', 'ḯ' => 'ḯ', 'Ḱ' => 'Ḱ', 'ḱ' => 'ḱ', 'Ḳ' => 'Ḳ', 'ḳ' => 'ḳ', 'Ḵ' => 'Ḵ', 'ḵ' => 'ḵ', 'Ḷ' => 'Ḷ', 'ḷ' => 'ḷ', 'Ḹ' => 'Ḹ', 'ḹ' => 'ḹ', 'Ḻ' => 'Ḻ', 'ḻ' => 'ḻ', 'Ḽ' => 'Ḽ', 'ḽ' => 'ḽ', 'Ḿ' => 'Ḿ', 'ḿ' => 'ḿ', 'Ṁ' => 'Ṁ', 'ṁ' => 'ṁ', 'Ṃ' => 'Ṃ', 'ṃ' => 'ṃ', 'Ṅ' => 'Ṅ', 'ṅ' => 'ṅ', 'Ṇ' => 'Ṇ', 'ṇ' => 'ṇ', 'Ṉ' => 'Ṉ', 'ṉ' => 'ṉ', 'Ṋ' => 'Ṋ', 'ṋ' => 'ṋ', 'Ṍ' => 'Ṍ', 'ṍ' => 'ṍ', 'Ṏ' => 'Ṏ', 'ṏ' => 'ṏ', 'Ṑ' => 'Ṑ', 'ṑ' => 'ṑ', 'Ṓ' => 'Ṓ', 'ṓ' => 'ṓ', 'Ṕ' => 'Ṕ', 'ṕ' => 'ṕ', 'Ṗ' => 'Ṗ', 'ṗ' => 'ṗ', 'Ṙ' => 'Ṙ', 'ṙ' => 'ṙ', 'Ṛ' => 'Ṛ', 'ṛ' => 'ṛ', 'Ṝ' => 'Ṝ', 'ṝ' => 'ṝ', 'Ṟ' => 'Ṟ', 'ṟ' => 'ṟ', 'Ṡ' => 'Ṡ', 'ṡ' => 'ṡ', 'Ṣ' => 'Ṣ', 'ṣ' => 'ṣ', 'Ṥ' => 'Ṥ', 'ṥ' => 'ṥ', 'Ṧ' => 'Ṧ', 'ṧ' => 'ṧ', 'Ṩ' => 'Ṩ', 'ṩ' => 'ṩ', 'Ṫ' => 'Ṫ', 'ṫ' => 'ṫ', 'Ṭ' => 'Ṭ', 'ṭ' => 'ṭ', 'Ṯ' => 'Ṯ', 'ṯ' => 'ṯ', 'Ṱ' => 'Ṱ', 'ṱ' => 'ṱ', 'Ṳ' => 'Ṳ', 'ṳ' => 'ṳ', 'Ṵ' => 'Ṵ', 'ṵ' => 'ṵ', 'Ṷ' => 'Ṷ', 'ṷ' => 'ṷ', 'Ṹ' => 'Ṹ', 'ṹ' => 'ṹ', 'Ṻ' => 'Ṻ', 'ṻ' => 'ṻ', 'Ṽ' => 'Ṽ', 'ṽ' => 'ṽ', 'Ṿ' => 'Ṿ', 'ṿ' => 'ṿ', 'Ẁ' => 'Ẁ', 'ẁ' => 'ẁ', 'Ẃ' => 'Ẃ', 'ẃ' => 'ẃ', 'Ẅ' => 'Ẅ', 'ẅ' => 'ẅ', 'Ẇ' => 'Ẇ', 'ẇ' => 'ẇ', 'Ẉ' => 'Ẉ', 'ẉ' => 'ẉ', 'Ẋ' => 'Ẋ', 'ẋ' => 'ẋ', 'Ẍ' => 'Ẍ', 'ẍ' => 'ẍ', 'Ẏ' => 'Ẏ', 'ẏ' => 'ẏ', 'Ẑ' => 'Ẑ', 'ẑ' => 'ẑ', 'Ẓ' => 'Ẓ', 'ẓ' => 'ẓ', 'Ẕ' => 'Ẕ', 'ẕ' => 'ẕ', 'ẖ' => 'ẖ', 'ẗ' => 'ẗ', 'ẘ' => 'ẘ', 'ẙ' => 'ẙ', 'ẛ' => 'ẛ', 'Ạ' => 'Ạ', 'ạ' => 'ạ', 'Ả' => 'Ả', 'ả' => 'ả', 'Ấ' => 'Ấ', 'ấ' => 'ấ', 'Ầ' => 'Ầ', 'ầ' => 'ầ', 'Ẩ' => 'Ẩ', 'ẩ' => 'ẩ', 'Ẫ' => 'Ẫ', 'ẫ' => 'ẫ', 'Ậ' => 'Ậ', 'ậ' => 'ậ', 'Ắ' => 'Ắ', 'ắ' => 'ắ', 'Ằ' => 'Ằ', 'ằ' => 'ằ', 'Ẳ' => 'Ẳ', 'ẳ' => 'ẳ', 'Ẵ' => 'Ẵ', 'ẵ' => 'ẵ', 'Ặ' => 'Ặ', 'ặ' => 'ặ', 'Ẹ' => 'Ẹ', 'ẹ' => 'ẹ', 'Ẻ' => 'Ẻ', 'ẻ' => 'ẻ', 'Ẽ' => 'Ẽ', 'ẽ' => 'ẽ', 'Ế' => 'Ế', 'ế' => 'ế', 'Ề' => 'Ề', 'ề' => 'ề', 'Ể' => 'Ể', 'ể' => 'ể', 'Ễ' => 'Ễ', 'ễ' => 'ễ', 'Ệ' => 'Ệ', 'ệ' => 'ệ', 'Ỉ' => 'Ỉ', 'ỉ' => 'ỉ', 'Ị' => 'Ị', 'ị' => 'ị', 'Ọ' => 'Ọ', 'ọ' => 'ọ', 'Ỏ' => 'Ỏ', 'ỏ' => 'ỏ', 'Ố' => 'Ố', 'ố' => 'ố', 'Ồ' => 'Ồ', 'ồ' => 'ồ', 'Ổ' => 'Ổ', 'ổ' => 'ổ', 'Ỗ' => 'Ỗ', 'ỗ' => 'ỗ', 'Ộ' => 'Ộ', 'ộ' => 'ộ', 'Ớ' => 'Ớ', 'ớ' => 'ớ', 'Ờ' => 'Ờ', 'ờ' => 'ờ', 'Ở' => 'Ở', 'ở' => 'ở', 'Ỡ' => 'Ỡ', 'ỡ' => 'ỡ', 'Ợ' => 'Ợ', 'ợ' => 'ợ', 'Ụ' => 'Ụ', 'ụ' => 'ụ', 'Ủ' => 'Ủ', 'ủ' => 'ủ', 'Ứ' => 'Ứ', 'ứ' => 'ứ', 'Ừ' => 'Ừ', 'ừ' => 'ừ', 'Ử' => 'Ử', 'ử' => 'ử', 'Ữ' => 'Ữ', 'ữ' => 'ữ', 'Ự' => 'Ự', 'ự' => 'ự', 'Ỳ' => 'Ỳ', 'ỳ' => 'ỳ', 'Ỵ' => 'Ỵ', 'ỵ' => 'ỵ', 'Ỷ' => 'Ỷ', 'ỷ' => 'ỷ', 'Ỹ' => 'Ỹ', 'ỹ' => 'ỹ', 'ἀ' => 'ἀ', 'ἁ' => 'ἁ', 'ἂ' => 'ἂ', 'ἃ' => 'ἃ', 'ἄ' => 'ἄ', 'ἅ' => 'ἅ', 'ἆ' => 'ἆ', 'ἇ' => 'ἇ', 'Ἀ' => 'Ἀ', 'Ἁ' => 'Ἁ', 'Ἂ' => 'Ἂ', 'Ἃ' => 'Ἃ', 'Ἄ' => 'Ἄ', 'Ἅ' => 'Ἅ', 'Ἆ' => 'Ἆ', 'Ἇ' => 'Ἇ', 'ἐ' => 'ἐ', 'ἑ' => 'ἑ', 'ἒ' => 'ἒ', 'ἓ' => 'ἓ', 'ἔ' => 'ἔ', 'ἕ' => 'ἕ', 'Ἐ' => 'Ἐ', 'Ἑ' => 'Ἑ', 'Ἒ' => 'Ἒ', 'Ἓ' => 'Ἓ', 'Ἔ' => 'Ἔ', 'Ἕ' => 'Ἕ', 'ἠ' => 'ἠ', 'ἡ' => 'ἡ', 'ἢ' => 'ἢ', 'ἣ' => 'ἣ', 'ἤ' => 'ἤ', 'ἥ' => 'ἥ', 'ἦ' => 'ἦ', 'ἧ' => 'ἧ', 'Ἠ' => 'Ἠ', 'Ἡ' => 'Ἡ', 'Ἢ' => 'Ἢ', 'Ἣ' => 'Ἣ', 'Ἤ' => 'Ἤ', 'Ἥ' => 'Ἥ', 'Ἦ' => 'Ἦ', 'Ἧ' => 'Ἧ', 'ἰ' => 'ἰ', 'ἱ' => 'ἱ', 'ἲ' => 'ἲ', 'ἳ' => 'ἳ', 'ἴ' => 'ἴ', 'ἵ' => 'ἵ', 'ἶ' => 'ἶ', 'ἷ' => 'ἷ', 'Ἰ' => 'Ἰ', 'Ἱ' => 'Ἱ', 'Ἲ' => 'Ἲ', 'Ἳ' => 'Ἳ', 'Ἴ' => 'Ἴ', 'Ἵ' => 'Ἵ', 'Ἶ' => 'Ἶ', 'Ἷ' => 'Ἷ', 'ὀ' => 'ὀ', 'ὁ' => 'ὁ', 'ὂ' => 'ὂ', 'ὃ' => 'ὃ', 'ὄ' => 'ὄ', 'ὅ' => 'ὅ', 'Ὀ' => 'Ὀ', 'Ὁ' => 'Ὁ', 'Ὂ' => 'Ὂ', 'Ὃ' => 'Ὃ', 'Ὄ' => 'Ὄ', 'Ὅ' => 'Ὅ', 'ὐ' => 'ὐ', 'ὑ' => 'ὑ', 'ὒ' => 'ὒ', 'ὓ' => 'ὓ', 'ὔ' => 'ὔ', 'ὕ' => 'ὕ', 'ὖ' => 'ὖ', 'ὗ' => 'ὗ', 'Ὑ' => 'Ὑ', 'Ὓ' => 'Ὓ', 'Ὕ' => 'Ὕ', 'Ὗ' => 'Ὗ', 'ὠ' => 'ὠ', 'ὡ' => 'ὡ', 'ὢ' => 'ὢ', 'ὣ' => 'ὣ', 'ὤ' => 'ὤ', 'ὥ' => 'ὥ', 'ὦ' => 'ὦ', 'ὧ' => 'ὧ', 'Ὠ' => 'Ὠ', 'Ὡ' => 'Ὡ', 'Ὢ' => 'Ὢ', 'Ὣ' => 'Ὣ', 'Ὤ' => 'Ὤ', 'Ὥ' => 'Ὥ', 'Ὦ' => 'Ὦ', 'Ὧ' => 'Ὧ', 'ὰ' => 'ὰ', 'ὲ' => 'ὲ', 'ὴ' => 'ὴ', 'ὶ' => 'ὶ', 'ὸ' => 'ὸ', 'ὺ' => 'ὺ', 'ὼ' => 'ὼ', 'ᾀ' => 'ᾀ', 'ᾁ' => 'ᾁ', 'ᾂ' => 'ᾂ', 'ᾃ' => 'ᾃ', 'ᾄ' => 'ᾄ', 'ᾅ' => 'ᾅ', 'ᾆ' => 'ᾆ', 'ᾇ' => 'ᾇ', 'ᾈ' => 'ᾈ', 'ᾉ' => 'ᾉ', 'ᾊ' => 'ᾊ', 'ᾋ' => 'ᾋ', 'ᾌ' => 'ᾌ', 'ᾍ' => 'ᾍ', 'ᾎ' => 'ᾎ', 'ᾏ' => 'ᾏ', 'ᾐ' => 'ᾐ', 'ᾑ' => 'ᾑ', 'ᾒ' => 'ᾒ', 'ᾓ' => 'ᾓ', 'ᾔ' => 'ᾔ', 'ᾕ' => 'ᾕ', 'ᾖ' => 'ᾖ', 'ᾗ' => 'ᾗ', 'ᾘ' => 'ᾘ', 'ᾙ' => 'ᾙ', 'ᾚ' => 'ᾚ', 'ᾛ' => 'ᾛ', 'ᾜ' => 'ᾜ', 'ᾝ' => 'ᾝ', 'ᾞ' => 'ᾞ', 'ᾟ' => 'ᾟ', 'ᾠ' => 'ᾠ', 'ᾡ' => 'ᾡ', 'ᾢ' => 'ᾢ', 'ᾣ' => 'ᾣ', 'ᾤ' => 'ᾤ', 'ᾥ' => 'ᾥ', 'ᾦ' => 'ᾦ', 'ᾧ' => 'ᾧ', 'ᾨ' => 'ᾨ', 'ᾩ' => 'ᾩ', 'ᾪ' => 'ᾪ', 'ᾫ' => 'ᾫ', 'ᾬ' => 'ᾬ', 'ᾭ' => 'ᾭ', 'ᾮ' => 'ᾮ', 'ᾯ' => 'ᾯ', 'ᾰ' => 'ᾰ', 'ᾱ' => 'ᾱ', 'ᾲ' => 'ᾲ', 'ᾳ' => 'ᾳ', 'ᾴ' => 'ᾴ', 'ᾶ' => 'ᾶ', 'ᾷ' => 'ᾷ', 'Ᾰ' => 'Ᾰ', 'Ᾱ' => 'Ᾱ', 'Ὰ' => 'Ὰ', 'ᾼ' => 'ᾼ', '῁' => '῁', 'ῂ' => 'ῂ', 'ῃ' => 'ῃ', 'ῄ' => 'ῄ', 'ῆ' => 'ῆ', 'ῇ' => 'ῇ', 'Ὲ' => 'Ὲ', 'Ὴ' => 'Ὴ', 'ῌ' => 'ῌ', '῍' => '῍', '῎' => '῎', '῏' => '῏', 'ῐ' => 'ῐ', 'ῑ' => 'ῑ', 'ῒ' => 'ῒ', 'ῖ' => 'ῖ', 'ῗ' => 'ῗ', 'Ῐ' => 'Ῐ', 'Ῑ' => 'Ῑ', 'Ὶ' => 'Ὶ', '῝' => '῝', '῞' => '῞', '῟' => '῟', 'ῠ' => 'ῠ', 'ῡ' => 'ῡ', 'ῢ' => 'ῢ', 'ῤ' => 'ῤ', 'ῥ' => 'ῥ', 'ῦ' => 'ῦ', 'ῧ' => 'ῧ', 'Ῠ' => 'Ῠ', 'Ῡ' => 'Ῡ', 'Ὺ' => 'Ὺ', 'Ῥ' => 'Ῥ', '῭' => '῭', 'ῲ' => 'ῲ', 'ῳ' => 'ῳ', 'ῴ' => 'ῴ', 'ῶ' => 'ῶ', 'ῷ' => 'ῷ', 'Ὸ' => 'Ὸ', 'Ὼ' => 'Ὼ', 'ῼ' => 'ῼ', '↚' => '↚', '↛' => '↛', '↮' => '↮', '⇍' => '⇍', '⇎' => '⇎', '⇏' => '⇏', '∄' => '∄', '∉' => '∉', '∌' => '∌', '∤' => '∤', '∦' => '∦', '≁' => '≁', '≄' => '≄', '≇' => '≇', '≉' => '≉', '≠' => '≠', '≢' => '≢', '≭' => '≭', '≮' => '≮', '≯' => '≯', '≰' => '≰', '≱' => '≱', '≴' => '≴', '≵' => '≵', '≸' => '≸', '≹' => '≹', '⊀' => '⊀', '⊁' => '⊁', '⊄' => '⊄', '⊅' => '⊅', '⊈' => '⊈', '⊉' => '⊉', '⊬' => '⊬', '⊭' => '⊭', '⊮' => '⊮', '⊯' => '⊯', '⋠' => '⋠', '⋡' => '⋡', '⋢' => '⋢', '⋣' => '⋣', '⋪' => '⋪', '⋫' => '⋫', '⋬' => '⋬', '⋭' => '⋭', 'が' => 'が', 'ぎ' => 'ぎ', 'ぐ' => 'ぐ', 'げ' => 'げ', 'ご' => 'ご', 'ざ' => 'ざ', 'じ' => 'じ', 'ず' => 'ず', 'ぜ' => 'ぜ', 'ぞ' => 'ぞ', 'だ' => 'だ', 'ぢ' => 'ぢ', 'づ' => 'づ', 'で' => 'で', 'ど' => 'ど', 'ば' => 'ば', 'ぱ' => 'ぱ', 'び' => 'び', 'ぴ' => 'ぴ', 'ぶ' => 'ぶ', 'ぷ' => 'ぷ', 'べ' => 'べ', 'ぺ' => 'ぺ', 'ぼ' => 'ぼ', 'ぽ' => 'ぽ', 'ゔ' => 'ゔ', 'ゞ' => 'ゞ', 'ガ' => 'ガ', 'ギ' => 'ギ', 'グ' => 'グ', 'ゲ' => 'ゲ', 'ゴ' => 'ゴ', 'ザ' => 'ザ', 'ジ' => 'ジ', 'ズ' => 'ズ', 'ゼ' => 'ゼ', 'ゾ' => 'ゾ', 'ダ' => 'ダ', 'ヂ' => 'ヂ', 'ヅ' => 'ヅ', 'デ' => 'デ', 'ド' => 'ド', 'バ' => 'バ', 'パ' => 'パ', 'ビ' => 'ビ', 'ピ' => 'ピ', 'ブ' => 'ブ', 'プ' => 'プ', 'ベ' => 'ベ', 'ペ' => 'ペ', 'ボ' => 'ボ', 'ポ' => 'ポ', 'ヴ' => 'ヴ', 'ヷ' => 'ヷ', 'ヸ' => 'ヸ', 'ヹ' => 'ヹ', 'ヺ' => 'ヺ', 'ヾ' => 'ヾ', '𑂚' => '𑂚', '𑂜' => '𑂜', '𑂫' => '𑂫', '𑄮' => '𑄮', '𑄯' => '𑄯', '𑍋' => '𑍋', '𑍌' => '𑍌', '𑒻' => '𑒻', '𑒼' => '𑒼', '𑒾' => '𑒾', '𑖺' => '𑖺', '𑖻' => '𑖻', '𑤸' => '𑤸'); diff --git a/vendor-bundle/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php b/vendor-bundle/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php new file mode 100644 index 000000000..9fa355c22 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php @@ -0,0 +1,5 @@ + 'À', 'Á' => 'Á', 'Â' => 'Â', 'Ã' => 'Ã', 'Ä' => 'Ä', 'Å' => 'Å', 'Ç' => 'Ç', 'È' => 'È', 'É' => 'É', 'Ê' => 'Ê', 'Ë' => 'Ë', 'Ì' => 'Ì', 'Í' => 'Í', 'Î' => 'Î', 'Ï' => 'Ï', 'Ñ' => 'Ñ', 'Ò' => 'Ò', 'Ó' => 'Ó', 'Ô' => 'Ô', 'Õ' => 'Õ', 'Ö' => 'Ö', 'Ù' => 'Ù', 'Ú' => 'Ú', 'Û' => 'Û', 'Ü' => 'Ü', 'Ý' => 'Ý', 'à' => 'à', 'á' => 'á', 'â' => 'â', 'ã' => 'ã', 'ä' => 'ä', 'å' => 'å', 'ç' => 'ç', 'è' => 'è', 'é' => 'é', 'ê' => 'ê', 'ë' => 'ë', 'ì' => 'ì', 'í' => 'í', 'î' => 'î', 'ï' => 'ï', 'ñ' => 'ñ', 'ò' => 'ò', 'ó' => 'ó', 'ô' => 'ô', 'õ' => 'õ', 'ö' => 'ö', 'ù' => 'ù', 'ú' => 'ú', 'û' => 'û', 'ü' => 'ü', 'ý' => 'ý', 'ÿ' => 'ÿ', 'Ā' => 'Ā', 'ā' => 'ā', 'Ă' => 'Ă', 'ă' => 'ă', 'Ą' => 'Ą', 'ą' => 'ą', 'Ć' => 'Ć', 'ć' => 'ć', 'Ĉ' => 'Ĉ', 'ĉ' => 'ĉ', 'Ċ' => 'Ċ', 'ċ' => 'ċ', 'Č' => 'Č', 'č' => 'č', 'Ď' => 'Ď', 'ď' => 'ď', 'Ē' => 'Ē', 'ē' => 'ē', 'Ĕ' => 'Ĕ', 'ĕ' => 'ĕ', 'Ė' => 'Ė', 'ė' => 'ė', 'Ę' => 'Ę', 'ę' => 'ę', 'Ě' => 'Ě', 'ě' => 'ě', 'Ĝ' => 'Ĝ', 'ĝ' => 'ĝ', 'Ğ' => 'Ğ', 'ğ' => 'ğ', 'Ġ' => 'Ġ', 'ġ' => 'ġ', 'Ģ' => 'Ģ', 'ģ' => 'ģ', 'Ĥ' => 'Ĥ', 'ĥ' => 'ĥ', 'Ĩ' => 'Ĩ', 'ĩ' => 'ĩ', 'Ī' => 'Ī', 'ī' => 'ī', 'Ĭ' => 'Ĭ', 'ĭ' => 'ĭ', 'Į' => 'Į', 'į' => 'į', 'İ' => 'İ', 'Ĵ' => 'Ĵ', 'ĵ' => 'ĵ', 'Ķ' => 'Ķ', 'ķ' => 'ķ', 'Ĺ' => 'Ĺ', 'ĺ' => 'ĺ', 'Ļ' => 'Ļ', 'ļ' => 'ļ', 'Ľ' => 'Ľ', 'ľ' => 'ľ', 'Ń' => 'Ń', 'ń' => 'ń', 'Ņ' => 'Ņ', 'ņ' => 'ņ', 'Ň' => 'Ň', 'ň' => 'ň', 'Ō' => 'Ō', 'ō' => 'ō', 'Ŏ' => 'Ŏ', 'ŏ' => 'ŏ', 'Ő' => 'Ő', 'ő' => 'ő', 'Ŕ' => 'Ŕ', 'ŕ' => 'ŕ', 'Ŗ' => 'Ŗ', 'ŗ' => 'ŗ', 'Ř' => 'Ř', 'ř' => 'ř', 'Ś' => 'Ś', 'ś' => 'ś', 'Ŝ' => 'Ŝ', 'ŝ' => 'ŝ', 'Ş' => 'Ş', 'ş' => 'ş', 'Š' => 'Š', 'š' => 'š', 'Ţ' => 'Ţ', 'ţ' => 'ţ', 'Ť' => 'Ť', 'ť' => 'ť', 'Ũ' => 'Ũ', 'ũ' => 'ũ', 'Ū' => 'Ū', 'ū' => 'ū', 'Ŭ' => 'Ŭ', 'ŭ' => 'ŭ', 'Ů' => 'Ů', 'ů' => 'ů', 'Ű' => 'Ű', 'ű' => 'ű', 'Ų' => 'Ų', 'ų' => 'ų', 'Ŵ' => 'Ŵ', 'ŵ' => 'ŵ', 'Ŷ' => 'Ŷ', 'ŷ' => 'ŷ', 'Ÿ' => 'Ÿ', 'Ź' => 'Ź', 'ź' => 'ź', 'Ż' => 'Ż', 'ż' => 'ż', 'Ž' => 'Ž', 'ž' => 'ž', 'Ơ' => 'Ơ', 'ơ' => 'ơ', 'Ư' => 'Ư', 'ư' => 'ư', 'Ǎ' => 'Ǎ', 'ǎ' => 'ǎ', 'Ǐ' => 'Ǐ', 'ǐ' => 'ǐ', 'Ǒ' => 'Ǒ', 'ǒ' => 'ǒ', 'Ǔ' => 'Ǔ', 'ǔ' => 'ǔ', 'Ǖ' => 'Ǖ', 'ǖ' => 'ǖ', 'Ǘ' => 'Ǘ', 'ǘ' => 'ǘ', 'Ǚ' => 'Ǚ', 'ǚ' => 'ǚ', 'Ǜ' => 'Ǜ', 'ǜ' => 'ǜ', 'Ǟ' => 'Ǟ', 'ǟ' => 'ǟ', 'Ǡ' => 'Ǡ', 'ǡ' => 'ǡ', 'Ǣ' => 'Ǣ', 'ǣ' => 'ǣ', 'Ǧ' => 'Ǧ', 'ǧ' => 'ǧ', 'Ǩ' => 'Ǩ', 'ǩ' => 'ǩ', 'Ǫ' => 'Ǫ', 'ǫ' => 'ǫ', 'Ǭ' => 'Ǭ', 'ǭ' => 'ǭ', 'Ǯ' => 'Ǯ', 'ǯ' => 'ǯ', 'ǰ' => 'ǰ', 'Ǵ' => 'Ǵ', 'ǵ' => 'ǵ', 'Ǹ' => 'Ǹ', 'ǹ' => 'ǹ', 'Ǻ' => 'Ǻ', 'ǻ' => 'ǻ', 'Ǽ' => 'Ǽ', 'ǽ' => 'ǽ', 'Ǿ' => 'Ǿ', 'ǿ' => 'ǿ', 'Ȁ' => 'Ȁ', 'ȁ' => 'ȁ', 'Ȃ' => 'Ȃ', 'ȃ' => 'ȃ', 'Ȅ' => 'Ȅ', 'ȅ' => 'ȅ', 'Ȇ' => 'Ȇ', 'ȇ' => 'ȇ', 'Ȉ' => 'Ȉ', 'ȉ' => 'ȉ', 'Ȋ' => 'Ȋ', 'ȋ' => 'ȋ', 'Ȍ' => 'Ȍ', 'ȍ' => 'ȍ', 'Ȏ' => 'Ȏ', 'ȏ' => 'ȏ', 'Ȑ' => 'Ȑ', 'ȑ' => 'ȑ', 'Ȓ' => 'Ȓ', 'ȓ' => 'ȓ', 'Ȕ' => 'Ȕ', 'ȕ' => 'ȕ', 'Ȗ' => 'Ȗ', 'ȗ' => 'ȗ', 'Ș' => 'Ș', 'ș' => 'ș', 'Ț' => 'Ț', 'ț' => 'ț', 'Ȟ' => 'Ȟ', 'ȟ' => 'ȟ', 'Ȧ' => 'Ȧ', 'ȧ' => 'ȧ', 'Ȩ' => 'Ȩ', 'ȩ' => 'ȩ', 'Ȫ' => 'Ȫ', 'ȫ' => 'ȫ', 'Ȭ' => 'Ȭ', 'ȭ' => 'ȭ', 'Ȯ' => 'Ȯ', 'ȯ' => 'ȯ', 'Ȱ' => 'Ȱ', 'ȱ' => 'ȱ', 'Ȳ' => 'Ȳ', 'ȳ' => 'ȳ', '̀' => '̀', '́' => '́', '̓' => '̓', '̈́' => '̈́', 'ʹ' => 'ʹ', ';' => ';', '΅' => '΅', 'Ά' => 'Ά', '·' => '·', 'Έ' => 'Έ', 'Ή' => 'Ή', 'Ί' => 'Ί', 'Ό' => 'Ό', 'Ύ' => 'Ύ', 'Ώ' => 'Ώ', 'ΐ' => 'ΐ', 'Ϊ' => 'Ϊ', 'Ϋ' => 'Ϋ', 'ά' => 'ά', 'έ' => 'έ', 'ή' => 'ή', 'ί' => 'ί', 'ΰ' => 'ΰ', 'ϊ' => 'ϊ', 'ϋ' => 'ϋ', 'ό' => 'ό', 'ύ' => 'ύ', 'ώ' => 'ώ', 'ϓ' => 'ϓ', 'ϔ' => 'ϔ', 'Ѐ' => 'Ѐ', 'Ё' => 'Ё', 'Ѓ' => 'Ѓ', 'Ї' => 'Ї', 'Ќ' => 'Ќ', 'Ѝ' => 'Ѝ', 'Ў' => 'Ў', 'Й' => 'Й', 'й' => 'й', 'ѐ' => 'ѐ', 'ё' => 'ё', 'ѓ' => 'ѓ', 'ї' => 'ї', 'ќ' => 'ќ', 'ѝ' => 'ѝ', 'ў' => 'ў', 'Ѷ' => 'Ѷ', 'ѷ' => 'ѷ', 'Ӂ' => 'Ӂ', 'ӂ' => 'ӂ', 'Ӑ' => 'Ӑ', 'ӑ' => 'ӑ', 'Ӓ' => 'Ӓ', 'ӓ' => 'ӓ', 'Ӗ' => 'Ӗ', 'ӗ' => 'ӗ', 'Ӛ' => 'Ӛ', 'ӛ' => 'ӛ', 'Ӝ' => 'Ӝ', 'ӝ' => 'ӝ', 'Ӟ' => 'Ӟ', 'ӟ' => 'ӟ', 'Ӣ' => 'Ӣ', 'ӣ' => 'ӣ', 'Ӥ' => 'Ӥ', 'ӥ' => 'ӥ', 'Ӧ' => 'Ӧ', 'ӧ' => 'ӧ', 'Ӫ' => 'Ӫ', 'ӫ' => 'ӫ', 'Ӭ' => 'Ӭ', 'ӭ' => 'ӭ', 'Ӯ' => 'Ӯ', 'ӯ' => 'ӯ', 'Ӱ' => 'Ӱ', 'ӱ' => 'ӱ', 'Ӳ' => 'Ӳ', 'ӳ' => 'ӳ', 'Ӵ' => 'Ӵ', 'ӵ' => 'ӵ', 'Ӹ' => 'Ӹ', 'ӹ' => 'ӹ', 'آ' => 'آ', 'أ' => 'أ', 'ؤ' => 'ؤ', 'إ' => 'إ', 'ئ' => 'ئ', 'ۀ' => 'ۀ', 'ۂ' => 'ۂ', 'ۓ' => 'ۓ', 'ऩ' => 'ऩ', 'ऱ' => 'ऱ', 'ऴ' => 'ऴ', 'क़' => 'क़', 'ख़' => 'ख़', 'ग़' => 'ग़', 'ज़' => 'ज़', 'ड़' => 'ड़', 'ढ़' => 'ढ़', 'फ़' => 'फ़', 'य़' => 'य़', 'ো' => 'ো', 'ৌ' => 'ৌ', 'ড়' => 'ড়', 'ঢ়' => 'ঢ়', 'য়' => 'য়', 'ਲ਼' => 'ਲ਼', 'ਸ਼' => 'ਸ਼', 'ਖ਼' => 'ਖ਼', 'ਗ਼' => 'ਗ਼', 'ਜ਼' => 'ਜ਼', 'ਫ਼' => 'ਫ਼', 'ୈ' => 'ୈ', 'ୋ' => 'ୋ', 'ୌ' => 'ୌ', 'ଡ଼' => 'ଡ଼', 'ଢ଼' => 'ଢ଼', 'ஔ' => 'ஔ', 'ொ' => 'ொ', 'ோ' => 'ோ', 'ௌ' => 'ௌ', 'ై' => 'ై', 'ೀ' => 'ೀ', 'ೇ' => 'ೇ', 'ೈ' => 'ೈ', 'ೊ' => 'ೊ', 'ೋ' => 'ೋ', 'ൊ' => 'ൊ', 'ോ' => 'ോ', 'ൌ' => 'ൌ', 'ේ' => 'ේ', 'ො' => 'ො', 'ෝ' => 'ෝ', 'ෞ' => 'ෞ', 'གྷ' => 'གྷ', 'ཌྷ' => 'ཌྷ', 'དྷ' => 'དྷ', 'བྷ' => 'བྷ', 'ཛྷ' => 'ཛྷ', 'ཀྵ' => 'ཀྵ', 'ཱི' => 'ཱི', 'ཱུ' => 'ཱུ', 'ྲྀ' => 'ྲྀ', 'ླྀ' => 'ླྀ', 'ཱྀ' => 'ཱྀ', 'ྒྷ' => 'ྒྷ', 'ྜྷ' => 'ྜྷ', 'ྡྷ' => 'ྡྷ', 'ྦྷ' => 'ྦྷ', 'ྫྷ' => 'ྫྷ', 'ྐྵ' => 'ྐྵ', 'ဦ' => 'ဦ', 'ᬆ' => 'ᬆ', 'ᬈ' => 'ᬈ', 'ᬊ' => 'ᬊ', 'ᬌ' => 'ᬌ', 'ᬎ' => 'ᬎ', 'ᬒ' => 'ᬒ', 'ᬻ' => 'ᬻ', 'ᬽ' => 'ᬽ', 'ᭀ' => 'ᭀ', 'ᭁ' => 'ᭁ', 'ᭃ' => 'ᭃ', 'Ḁ' => 'Ḁ', 'ḁ' => 'ḁ', 'Ḃ' => 'Ḃ', 'ḃ' => 'ḃ', 'Ḅ' => 'Ḅ', 'ḅ' => 'ḅ', 'Ḇ' => 'Ḇ', 'ḇ' => 'ḇ', 'Ḉ' => 'Ḉ', 'ḉ' => 'ḉ', 'Ḋ' => 'Ḋ', 'ḋ' => 'ḋ', 'Ḍ' => 'Ḍ', 'ḍ' => 'ḍ', 'Ḏ' => 'Ḏ', 'ḏ' => 'ḏ', 'Ḑ' => 'Ḑ', 'ḑ' => 'ḑ', 'Ḓ' => 'Ḓ', 'ḓ' => 'ḓ', 'Ḕ' => 'Ḕ', 'ḕ' => 'ḕ', 'Ḗ' => 'Ḗ', 'ḗ' => 'ḗ', 'Ḙ' => 'Ḙ', 'ḙ' => 'ḙ', 'Ḛ' => 'Ḛ', 'ḛ' => 'ḛ', 'Ḝ' => 'Ḝ', 'ḝ' => 'ḝ', 'Ḟ' => 'Ḟ', 'ḟ' => 'ḟ', 'Ḡ' => 'Ḡ', 'ḡ' => 'ḡ', 'Ḣ' => 'Ḣ', 'ḣ' => 'ḣ', 'Ḥ' => 'Ḥ', 'ḥ' => 'ḥ', 'Ḧ' => 'Ḧ', 'ḧ' => 'ḧ', 'Ḩ' => 'Ḩ', 'ḩ' => 'ḩ', 'Ḫ' => 'Ḫ', 'ḫ' => 'ḫ', 'Ḭ' => 'Ḭ', 'ḭ' => 'ḭ', 'Ḯ' => 'Ḯ', 'ḯ' => 'ḯ', 'Ḱ' => 'Ḱ', 'ḱ' => 'ḱ', 'Ḳ' => 'Ḳ', 'ḳ' => 'ḳ', 'Ḵ' => 'Ḵ', 'ḵ' => 'ḵ', 'Ḷ' => 'Ḷ', 'ḷ' => 'ḷ', 'Ḹ' => 'Ḹ', 'ḹ' => 'ḹ', 'Ḻ' => 'Ḻ', 'ḻ' => 'ḻ', 'Ḽ' => 'Ḽ', 'ḽ' => 'ḽ', 'Ḿ' => 'Ḿ', 'ḿ' => 'ḿ', 'Ṁ' => 'Ṁ', 'ṁ' => 'ṁ', 'Ṃ' => 'Ṃ', 'ṃ' => 'ṃ', 'Ṅ' => 'Ṅ', 'ṅ' => 'ṅ', 'Ṇ' => 'Ṇ', 'ṇ' => 'ṇ', 'Ṉ' => 'Ṉ', 'ṉ' => 'ṉ', 'Ṋ' => 'Ṋ', 'ṋ' => 'ṋ', 'Ṍ' => 'Ṍ', 'ṍ' => 'ṍ', 'Ṏ' => 'Ṏ', 'ṏ' => 'ṏ', 'Ṑ' => 'Ṑ', 'ṑ' => 'ṑ', 'Ṓ' => 'Ṓ', 'ṓ' => 'ṓ', 'Ṕ' => 'Ṕ', 'ṕ' => 'ṕ', 'Ṗ' => 'Ṗ', 'ṗ' => 'ṗ', 'Ṙ' => 'Ṙ', 'ṙ' => 'ṙ', 'Ṛ' => 'Ṛ', 'ṛ' => 'ṛ', 'Ṝ' => 'Ṝ', 'ṝ' => 'ṝ', 'Ṟ' => 'Ṟ', 'ṟ' => 'ṟ', 'Ṡ' => 'Ṡ', 'ṡ' => 'ṡ', 'Ṣ' => 'Ṣ', 'ṣ' => 'ṣ', 'Ṥ' => 'Ṥ', 'ṥ' => 'ṥ', 'Ṧ' => 'Ṧ', 'ṧ' => 'ṧ', 'Ṩ' => 'Ṩ', 'ṩ' => 'ṩ', 'Ṫ' => 'Ṫ', 'ṫ' => 'ṫ', 'Ṭ' => 'Ṭ', 'ṭ' => 'ṭ', 'Ṯ' => 'Ṯ', 'ṯ' => 'ṯ', 'Ṱ' => 'Ṱ', 'ṱ' => 'ṱ', 'Ṳ' => 'Ṳ', 'ṳ' => 'ṳ', 'Ṵ' => 'Ṵ', 'ṵ' => 'ṵ', 'Ṷ' => 'Ṷ', 'ṷ' => 'ṷ', 'Ṹ' => 'Ṹ', 'ṹ' => 'ṹ', 'Ṻ' => 'Ṻ', 'ṻ' => 'ṻ', 'Ṽ' => 'Ṽ', 'ṽ' => 'ṽ', 'Ṿ' => 'Ṿ', 'ṿ' => 'ṿ', 'Ẁ' => 'Ẁ', 'ẁ' => 'ẁ', 'Ẃ' => 'Ẃ', 'ẃ' => 'ẃ', 'Ẅ' => 'Ẅ', 'ẅ' => 'ẅ', 'Ẇ' => 'Ẇ', 'ẇ' => 'ẇ', 'Ẉ' => 'Ẉ', 'ẉ' => 'ẉ', 'Ẋ' => 'Ẋ', 'ẋ' => 'ẋ', 'Ẍ' => 'Ẍ', 'ẍ' => 'ẍ', 'Ẏ' => 'Ẏ', 'ẏ' => 'ẏ', 'Ẑ' => 'Ẑ', 'ẑ' => 'ẑ', 'Ẓ' => 'Ẓ', 'ẓ' => 'ẓ', 'Ẕ' => 'Ẕ', 'ẕ' => 'ẕ', 'ẖ' => 'ẖ', 'ẗ' => 'ẗ', 'ẘ' => 'ẘ', 'ẙ' => 'ẙ', 'ẛ' => 'ẛ', 'Ạ' => 'Ạ', 'ạ' => 'ạ', 'Ả' => 'Ả', 'ả' => 'ả', 'Ấ' => 'Ấ', 'ấ' => 'ấ', 'Ầ' => 'Ầ', 'ầ' => 'ầ', 'Ẩ' => 'Ẩ', 'ẩ' => 'ẩ', 'Ẫ' => 'Ẫ', 'ẫ' => 'ẫ', 'Ậ' => 'Ậ', 'ậ' => 'ậ', 'Ắ' => 'Ắ', 'ắ' => 'ắ', 'Ằ' => 'Ằ', 'ằ' => 'ằ', 'Ẳ' => 'Ẳ', 'ẳ' => 'ẳ', 'Ẵ' => 'Ẵ', 'ẵ' => 'ẵ', 'Ặ' => 'Ặ', 'ặ' => 'ặ', 'Ẹ' => 'Ẹ', 'ẹ' => 'ẹ', 'Ẻ' => 'Ẻ', 'ẻ' => 'ẻ', 'Ẽ' => 'Ẽ', 'ẽ' => 'ẽ', 'Ế' => 'Ế', 'ế' => 'ế', 'Ề' => 'Ề', 'ề' => 'ề', 'Ể' => 'Ể', 'ể' => 'ể', 'Ễ' => 'Ễ', 'ễ' => 'ễ', 'Ệ' => 'Ệ', 'ệ' => 'ệ', 'Ỉ' => 'Ỉ', 'ỉ' => 'ỉ', 'Ị' => 'Ị', 'ị' => 'ị', 'Ọ' => 'Ọ', 'ọ' => 'ọ', 'Ỏ' => 'Ỏ', 'ỏ' => 'ỏ', 'Ố' => 'Ố', 'ố' => 'ố', 'Ồ' => 'Ồ', 'ồ' => 'ồ', 'Ổ' => 'Ổ', 'ổ' => 'ổ', 'Ỗ' => 'Ỗ', 'ỗ' => 'ỗ', 'Ộ' => 'Ộ', 'ộ' => 'ộ', 'Ớ' => 'Ớ', 'ớ' => 'ớ', 'Ờ' => 'Ờ', 'ờ' => 'ờ', 'Ở' => 'Ở', 'ở' => 'ở', 'Ỡ' => 'Ỡ', 'ỡ' => 'ỡ', 'Ợ' => 'Ợ', 'ợ' => 'ợ', 'Ụ' => 'Ụ', 'ụ' => 'ụ', 'Ủ' => 'Ủ', 'ủ' => 'ủ', 'Ứ' => 'Ứ', 'ứ' => 'ứ', 'Ừ' => 'Ừ', 'ừ' => 'ừ', 'Ử' => 'Ử', 'ử' => 'ử', 'Ữ' => 'Ữ', 'ữ' => 'ữ', 'Ự' => 'Ự', 'ự' => 'ự', 'Ỳ' => 'Ỳ', 'ỳ' => 'ỳ', 'Ỵ' => 'Ỵ', 'ỵ' => 'ỵ', 'Ỷ' => 'Ỷ', 'ỷ' => 'ỷ', 'Ỹ' => 'Ỹ', 'ỹ' => 'ỹ', 'ἀ' => 'ἀ', 'ἁ' => 'ἁ', 'ἂ' => 'ἂ', 'ἃ' => 'ἃ', 'ἄ' => 'ἄ', 'ἅ' => 'ἅ', 'ἆ' => 'ἆ', 'ἇ' => 'ἇ', 'Ἀ' => 'Ἀ', 'Ἁ' => 'Ἁ', 'Ἂ' => 'Ἂ', 'Ἃ' => 'Ἃ', 'Ἄ' => 'Ἄ', 'Ἅ' => 'Ἅ', 'Ἆ' => 'Ἆ', 'Ἇ' => 'Ἇ', 'ἐ' => 'ἐ', 'ἑ' => 'ἑ', 'ἒ' => 'ἒ', 'ἓ' => 'ἓ', 'ἔ' => 'ἔ', 'ἕ' => 'ἕ', 'Ἐ' => 'Ἐ', 'Ἑ' => 'Ἑ', 'Ἒ' => 'Ἒ', 'Ἓ' => 'Ἓ', 'Ἔ' => 'Ἔ', 'Ἕ' => 'Ἕ', 'ἠ' => 'ἠ', 'ἡ' => 'ἡ', 'ἢ' => 'ἢ', 'ἣ' => 'ἣ', 'ἤ' => 'ἤ', 'ἥ' => 'ἥ', 'ἦ' => 'ἦ', 'ἧ' => 'ἧ', 'Ἠ' => 'Ἠ', 'Ἡ' => 'Ἡ', 'Ἢ' => 'Ἢ', 'Ἣ' => 'Ἣ', 'Ἤ' => 'Ἤ', 'Ἥ' => 'Ἥ', 'Ἦ' => 'Ἦ', 'Ἧ' => 'Ἧ', 'ἰ' => 'ἰ', 'ἱ' => 'ἱ', 'ἲ' => 'ἲ', 'ἳ' => 'ἳ', 'ἴ' => 'ἴ', 'ἵ' => 'ἵ', 'ἶ' => 'ἶ', 'ἷ' => 'ἷ', 'Ἰ' => 'Ἰ', 'Ἱ' => 'Ἱ', 'Ἲ' => 'Ἲ', 'Ἳ' => 'Ἳ', 'Ἴ' => 'Ἴ', 'Ἵ' => 'Ἵ', 'Ἶ' => 'Ἶ', 'Ἷ' => 'Ἷ', 'ὀ' => 'ὀ', 'ὁ' => 'ὁ', 'ὂ' => 'ὂ', 'ὃ' => 'ὃ', 'ὄ' => 'ὄ', 'ὅ' => 'ὅ', 'Ὀ' => 'Ὀ', 'Ὁ' => 'Ὁ', 'Ὂ' => 'Ὂ', 'Ὃ' => 'Ὃ', 'Ὄ' => 'Ὄ', 'Ὅ' => 'Ὅ', 'ὐ' => 'ὐ', 'ὑ' => 'ὑ', 'ὒ' => 'ὒ', 'ὓ' => 'ὓ', 'ὔ' => 'ὔ', 'ὕ' => 'ὕ', 'ὖ' => 'ὖ', 'ὗ' => 'ὗ', 'Ὑ' => 'Ὑ', 'Ὓ' => 'Ὓ', 'Ὕ' => 'Ὕ', 'Ὗ' => 'Ὗ', 'ὠ' => 'ὠ', 'ὡ' => 'ὡ', 'ὢ' => 'ὢ', 'ὣ' => 'ὣ', 'ὤ' => 'ὤ', 'ὥ' => 'ὥ', 'ὦ' => 'ὦ', 'ὧ' => 'ὧ', 'Ὠ' => 'Ὠ', 'Ὡ' => 'Ὡ', 'Ὢ' => 'Ὢ', 'Ὣ' => 'Ὣ', 'Ὤ' => 'Ὤ', 'Ὥ' => 'Ὥ', 'Ὦ' => 'Ὦ', 'Ὧ' => 'Ὧ', 'ὰ' => 'ὰ', 'ά' => 'ά', 'ὲ' => 'ὲ', 'έ' => 'έ', 'ὴ' => 'ὴ', 'ή' => 'ή', 'ὶ' => 'ὶ', 'ί' => 'ί', 'ὸ' => 'ὸ', 'ό' => 'ό', 'ὺ' => 'ὺ', 'ύ' => 'ύ', 'ὼ' => 'ὼ', 'ώ' => 'ώ', 'ᾀ' => 'ᾀ', 'ᾁ' => 'ᾁ', 'ᾂ' => 'ᾂ', 'ᾃ' => 'ᾃ', 'ᾄ' => 'ᾄ', 'ᾅ' => 'ᾅ', 'ᾆ' => 'ᾆ', 'ᾇ' => 'ᾇ', 'ᾈ' => 'ᾈ', 'ᾉ' => 'ᾉ', 'ᾊ' => 'ᾊ', 'ᾋ' => 'ᾋ', 'ᾌ' => 'ᾌ', 'ᾍ' => 'ᾍ', 'ᾎ' => 'ᾎ', 'ᾏ' => 'ᾏ', 'ᾐ' => 'ᾐ', 'ᾑ' => 'ᾑ', 'ᾒ' => 'ᾒ', 'ᾓ' => 'ᾓ', 'ᾔ' => 'ᾔ', 'ᾕ' => 'ᾕ', 'ᾖ' => 'ᾖ', 'ᾗ' => 'ᾗ', 'ᾘ' => 'ᾘ', 'ᾙ' => 'ᾙ', 'ᾚ' => 'ᾚ', 'ᾛ' => 'ᾛ', 'ᾜ' => 'ᾜ', 'ᾝ' => 'ᾝ', 'ᾞ' => 'ᾞ', 'ᾟ' => 'ᾟ', 'ᾠ' => 'ᾠ', 'ᾡ' => 'ᾡ', 'ᾢ' => 'ᾢ', 'ᾣ' => 'ᾣ', 'ᾤ' => 'ᾤ', 'ᾥ' => 'ᾥ', 'ᾦ' => 'ᾦ', 'ᾧ' => 'ᾧ', 'ᾨ' => 'ᾨ', 'ᾩ' => 'ᾩ', 'ᾪ' => 'ᾪ', 'ᾫ' => 'ᾫ', 'ᾬ' => 'ᾬ', 'ᾭ' => 'ᾭ', 'ᾮ' => 'ᾮ', 'ᾯ' => 'ᾯ', 'ᾰ' => 'ᾰ', 'ᾱ' => 'ᾱ', 'ᾲ' => 'ᾲ', 'ᾳ' => 'ᾳ', 'ᾴ' => 'ᾴ', 'ᾶ' => 'ᾶ', 'ᾷ' => 'ᾷ', 'Ᾰ' => 'Ᾰ', 'Ᾱ' => 'Ᾱ', 'Ὰ' => 'Ὰ', 'Ά' => 'Ά', 'ᾼ' => 'ᾼ', 'ι' => 'ι', '῁' => '῁', 'ῂ' => 'ῂ', 'ῃ' => 'ῃ', 'ῄ' => 'ῄ', 'ῆ' => 'ῆ', 'ῇ' => 'ῇ', 'Ὲ' => 'Ὲ', 'Έ' => 'Έ', 'Ὴ' => 'Ὴ', 'Ή' => 'Ή', 'ῌ' => 'ῌ', '῍' => '῍', '῎' => '῎', '῏' => '῏', 'ῐ' => 'ῐ', 'ῑ' => 'ῑ', 'ῒ' => 'ῒ', 'ΐ' => 'ΐ', 'ῖ' => 'ῖ', 'ῗ' => 'ῗ', 'Ῐ' => 'Ῐ', 'Ῑ' => 'Ῑ', 'Ὶ' => 'Ὶ', 'Ί' => 'Ί', '῝' => '῝', '῞' => '῞', '῟' => '῟', 'ῠ' => 'ῠ', 'ῡ' => 'ῡ', 'ῢ' => 'ῢ', 'ΰ' => 'ΰ', 'ῤ' => 'ῤ', 'ῥ' => 'ῥ', 'ῦ' => 'ῦ', 'ῧ' => 'ῧ', 'Ῠ' => 'Ῠ', 'Ῡ' => 'Ῡ', 'Ὺ' => 'Ὺ', 'Ύ' => 'Ύ', 'Ῥ' => 'Ῥ', '῭' => '῭', '΅' => '΅', '`' => '`', 'ῲ' => 'ῲ', 'ῳ' => 'ῳ', 'ῴ' => 'ῴ', 'ῶ' => 'ῶ', 'ῷ' => 'ῷ', 'Ὸ' => 'Ὸ', 'Ό' => 'Ό', 'Ὼ' => 'Ὼ', 'Ώ' => 'Ώ', 'ῼ' => 'ῼ', '´' => '´', ' ' => ' ', ' ' => ' ', 'Ω' => 'Ω', 'K' => 'K', 'Å' => 'Å', '↚' => '↚', '↛' => '↛', '↮' => '↮', '⇍' => '⇍', '⇎' => '⇎', '⇏' => '⇏', '∄' => '∄', '∉' => '∉', '∌' => '∌', '∤' => '∤', '∦' => '∦', '≁' => '≁', '≄' => '≄', '≇' => '≇', '≉' => '≉', '≠' => '≠', '≢' => '≢', '≭' => '≭', '≮' => '≮', '≯' => '≯', '≰' => '≰', '≱' => '≱', '≴' => '≴', '≵' => '≵', '≸' => '≸', '≹' => '≹', '⊀' => '⊀', '⊁' => '⊁', '⊄' => '⊄', '⊅' => '⊅', '⊈' => '⊈', '⊉' => '⊉', '⊬' => '⊬', '⊭' => '⊭', '⊮' => '⊮', '⊯' => '⊯', '⋠' => '⋠', '⋡' => '⋡', '⋢' => '⋢', '⋣' => '⋣', '⋪' => '⋪', '⋫' => '⋫', '⋬' => '⋬', '⋭' => '⋭', '〈' => '〈', '〉' => '〉', '⫝̸' => '⫝̸', 'が' => 'が', 'ぎ' => 'ぎ', 'ぐ' => 'ぐ', 'げ' => 'げ', 'ご' => 'ご', 'ざ' => 'ざ', 'じ' => 'じ', 'ず' => 'ず', 'ぜ' => 'ぜ', 'ぞ' => 'ぞ', 'だ' => 'だ', 'ぢ' => 'ぢ', 'づ' => 'づ', 'で' => 'で', 'ど' => 'ど', 'ば' => 'ば', 'ぱ' => 'ぱ', 'び' => 'び', 'ぴ' => 'ぴ', 'ぶ' => 'ぶ', 'ぷ' => 'ぷ', 'べ' => 'べ', 'ぺ' => 'ぺ', 'ぼ' => 'ぼ', 'ぽ' => 'ぽ', 'ゔ' => 'ゔ', 'ゞ' => 'ゞ', 'ガ' => 'ガ', 'ギ' => 'ギ', 'グ' => 'グ', 'ゲ' => 'ゲ', 'ゴ' => 'ゴ', 'ザ' => 'ザ', 'ジ' => 'ジ', 'ズ' => 'ズ', 'ゼ' => 'ゼ', 'ゾ' => 'ゾ', 'ダ' => 'ダ', 'ヂ' => 'ヂ', 'ヅ' => 'ヅ', 'デ' => 'デ', 'ド' => 'ド', 'バ' => 'バ', 'パ' => 'パ', 'ビ' => 'ビ', 'ピ' => 'ピ', 'ブ' => 'ブ', 'プ' => 'プ', 'ベ' => 'ベ', 'ペ' => 'ペ', 'ボ' => 'ボ', 'ポ' => 'ポ', 'ヴ' => 'ヴ', 'ヷ' => 'ヷ', 'ヸ' => 'ヸ', 'ヹ' => 'ヹ', 'ヺ' => 'ヺ', 'ヾ' => 'ヾ', '豈' => '豈', '更' => '更', '車' => '車', '賈' => '賈', '滑' => '滑', '串' => '串', '句' => '句', '龜' => '龜', '龜' => '龜', '契' => '契', '金' => '金', '喇' => '喇', '奈' => '奈', '懶' => '懶', '癩' => '癩', '羅' => '羅', '蘿' => '蘿', '螺' => '螺', '裸' => '裸', '邏' => '邏', '樂' => '樂', '洛' => '洛', '烙' => '烙', '珞' => '珞', '落' => '落', '酪' => '酪', '駱' => '駱', '亂' => '亂', '卵' => '卵', '欄' => '欄', '爛' => '爛', '蘭' => '蘭', '鸞' => '鸞', '嵐' => '嵐', '濫' => '濫', '藍' => '藍', '襤' => '襤', '拉' => '拉', '臘' => '臘', '蠟' => '蠟', '廊' => '廊', '朗' => '朗', '浪' => '浪', '狼' => '狼', '郎' => '郎', '來' => '來', '冷' => '冷', '勞' => '勞', '擄' => '擄', '櫓' => '櫓', '爐' => '爐', '盧' => '盧', '老' => '老', '蘆' => '蘆', '虜' => '虜', '路' => '路', '露' => '露', '魯' => '魯', '鷺' => '鷺', '碌' => '碌', '祿' => '祿', '綠' => '綠', '菉' => '菉', '錄' => '錄', '鹿' => '鹿', '論' => '論', '壟' => '壟', '弄' => '弄', '籠' => '籠', '聾' => '聾', '牢' => '牢', '磊' => '磊', '賂' => '賂', '雷' => '雷', '壘' => '壘', '屢' => '屢', '樓' => '樓', '淚' => '淚', '漏' => '漏', '累' => '累', '縷' => '縷', '陋' => '陋', '勒' => '勒', '肋' => '肋', '凜' => '凜', '凌' => '凌', '稜' => '稜', '綾' => '綾', '菱' => '菱', '陵' => '陵', '讀' => '讀', '拏' => '拏', '樂' => '樂', '諾' => '諾', '丹' => '丹', '寧' => '寧', '怒' => '怒', '率' => '率', '異' => '異', '北' => '北', '磻' => '磻', '便' => '便', '復' => '復', '不' => '不', '泌' => '泌', '數' => '數', '索' => '索', '參' => '參', '塞' => '塞', '省' => '省', '葉' => '葉', '說' => '說', '殺' => '殺', '辰' => '辰', '沈' => '沈', '拾' => '拾', '若' => '若', '掠' => '掠', '略' => '略', '亮' => '亮', '兩' => '兩', '凉' => '凉', '梁' => '梁', '糧' => '糧', '良' => '良', '諒' => '諒', '量' => '量', '勵' => '勵', '呂' => '呂', '女' => '女', '廬' => '廬', '旅' => '旅', '濾' => '濾', '礪' => '礪', '閭' => '閭', '驪' => '驪', '麗' => '麗', '黎' => '黎', '力' => '力', '曆' => '曆', '歷' => '歷', '轢' => '轢', '年' => '年', '憐' => '憐', '戀' => '戀', '撚' => '撚', '漣' => '漣', '煉' => '煉', '璉' => '璉', '秊' => '秊', '練' => '練', '聯' => '聯', '輦' => '輦', '蓮' => '蓮', '連' => '連', '鍊' => '鍊', '列' => '列', '劣' => '劣', '咽' => '咽', '烈' => '烈', '裂' => '裂', '說' => '說', '廉' => '廉', '念' => '念', '捻' => '捻', '殮' => '殮', '簾' => '簾', '獵' => '獵', '令' => '令', '囹' => '囹', '寧' => '寧', '嶺' => '嶺', '怜' => '怜', '玲' => '玲', '瑩' => '瑩', '羚' => '羚', '聆' => '聆', '鈴' => '鈴', '零' => '零', '靈' => '靈', '領' => '領', '例' => '例', '禮' => '禮', '醴' => '醴', '隸' => '隸', '惡' => '惡', '了' => '了', '僚' => '僚', '寮' => '寮', '尿' => '尿', '料' => '料', '樂' => '樂', '燎' => '燎', '療' => '療', '蓼' => '蓼', '遼' => '遼', '龍' => '龍', '暈' => '暈', '阮' => '阮', '劉' => '劉', '杻' => '杻', '柳' => '柳', '流' => '流', '溜' => '溜', '琉' => '琉', '留' => '留', '硫' => '硫', '紐' => '紐', '類' => '類', '六' => '六', '戮' => '戮', '陸' => '陸', '倫' => '倫', '崙' => '崙', '淪' => '淪', '輪' => '輪', '律' => '律', '慄' => '慄', '栗' => '栗', '率' => '率', '隆' => '隆', '利' => '利', '吏' => '吏', '履' => '履', '易' => '易', '李' => '李', '梨' => '梨', '泥' => '泥', '理' => '理', '痢' => '痢', '罹' => '罹', '裏' => '裏', '裡' => '裡', '里' => '里', '離' => '離', '匿' => '匿', '溺' => '溺', '吝' => '吝', '燐' => '燐', '璘' => '璘', '藺' => '藺', '隣' => '隣', '鱗' => '鱗', '麟' => '麟', '林' => '林', '淋' => '淋', '臨' => '臨', '立' => '立', '笠' => '笠', '粒' => '粒', '狀' => '狀', '炙' => '炙', '識' => '識', '什' => '什', '茶' => '茶', '刺' => '刺', '切' => '切', '度' => '度', '拓' => '拓', '糖' => '糖', '宅' => '宅', '洞' => '洞', '暴' => '暴', '輻' => '輻', '行' => '行', '降' => '降', '見' => '見', '廓' => '廓', '兀' => '兀', '嗀' => '嗀', '塚' => '塚', '晴' => '晴', '凞' => '凞', '猪' => '猪', '益' => '益', '礼' => '礼', '神' => '神', '祥' => '祥', '福' => '福', '靖' => '靖', '精' => '精', '羽' => '羽', '蘒' => '蘒', '諸' => '諸', '逸' => '逸', '都' => '都', '飯' => '飯', '飼' => '飼', '館' => '館', '鶴' => '鶴', '郞' => '郞', '隷' => '隷', '侮' => '侮', '僧' => '僧', '免' => '免', '勉' => '勉', '勤' => '勤', '卑' => '卑', '喝' => '喝', '嘆' => '嘆', '器' => '器', '塀' => '塀', '墨' => '墨', '層' => '層', '屮' => '屮', '悔' => '悔', '慨' => '慨', '憎' => '憎', '懲' => '懲', '敏' => '敏', '既' => '既', '暑' => '暑', '梅' => '梅', '海' => '海', '渚' => '渚', '漢' => '漢', '煮' => '煮', '爫' => '爫', '琢' => '琢', '碑' => '碑', '社' => '社', '祉' => '祉', '祈' => '祈', '祐' => '祐', '祖' => '祖', '祝' => '祝', '禍' => '禍', '禎' => '禎', '穀' => '穀', '突' => '突', '節' => '節', '練' => '練', '縉' => '縉', '繁' => '繁', '署' => '署', '者' => '者', '臭' => '臭', '艹' => '艹', '艹' => '艹', '著' => '著', '褐' => '褐', '視' => '視', '謁' => '謁', '謹' => '謹', '賓' => '賓', '贈' => '贈', '辶' => '辶', '逸' => '逸', '難' => '難', '響' => '響', '頻' => '頻', '恵' => '恵', '𤋮' => '𤋮', '舘' => '舘', '並' => '並', '况' => '况', '全' => '全', '侀' => '侀', '充' => '充', '冀' => '冀', '勇' => '勇', '勺' => '勺', '喝' => '喝', '啕' => '啕', '喙' => '喙', '嗢' => '嗢', '塚' => '塚', '墳' => '墳', '奄' => '奄', '奔' => '奔', '婢' => '婢', '嬨' => '嬨', '廒' => '廒', '廙' => '廙', '彩' => '彩', '徭' => '徭', '惘' => '惘', '慎' => '慎', '愈' => '愈', '憎' => '憎', '慠' => '慠', '懲' => '懲', '戴' => '戴', '揄' => '揄', '搜' => '搜', '摒' => '摒', '敖' => '敖', '晴' => '晴', '朗' => '朗', '望' => '望', '杖' => '杖', '歹' => '歹', '殺' => '殺', '流' => '流', '滛' => '滛', '滋' => '滋', '漢' => '漢', '瀞' => '瀞', '煮' => '煮', '瞧' => '瞧', '爵' => '爵', '犯' => '犯', '猪' => '猪', '瑱' => '瑱', '甆' => '甆', '画' => '画', '瘝' => '瘝', '瘟' => '瘟', '益' => '益', '盛' => '盛', '直' => '直', '睊' => '睊', '着' => '着', '磌' => '磌', '窱' => '窱', '節' => '節', '类' => '类', '絛' => '絛', '練' => '練', '缾' => '缾', '者' => '者', '荒' => '荒', '華' => '華', '蝹' => '蝹', '襁' => '襁', '覆' => '覆', '視' => '視', '調' => '調', '諸' => '諸', '請' => '請', '謁' => '謁', '諾' => '諾', '諭' => '諭', '謹' => '謹', '變' => '變', '贈' => '贈', '輸' => '輸', '遲' => '遲', '醙' => '醙', '鉶' => '鉶', '陼' => '陼', '難' => '難', '靖' => '靖', '韛' => '韛', '響' => '響', '頋' => '頋', '頻' => '頻', '鬒' => '鬒', '龜' => '龜', '𢡊' => '𢡊', '𢡄' => '𢡄', '𣏕' => '𣏕', '㮝' => '㮝', '䀘' => '䀘', '䀹' => '䀹', '𥉉' => '𥉉', '𥳐' => '𥳐', '𧻓' => '𧻓', '齃' => '齃', '龎' => '龎', 'יִ' => 'יִ', 'ײַ' => 'ײַ', 'שׁ' => 'שׁ', 'שׂ' => 'שׂ', 'שּׁ' => 'שּׁ', 'שּׂ' => 'שּׂ', 'אַ' => 'אַ', 'אָ' => 'אָ', 'אּ' => 'אּ', 'בּ' => 'בּ', 'גּ' => 'גּ', 'דּ' => 'דּ', 'הּ' => 'הּ', 'וּ' => 'וּ', 'זּ' => 'זּ', 'טּ' => 'טּ', 'יּ' => 'יּ', 'ךּ' => 'ךּ', 'כּ' => 'כּ', 'לּ' => 'לּ', 'מּ' => 'מּ', 'נּ' => 'נּ', 'סּ' => 'סּ', 'ףּ' => 'ףּ', 'פּ' => 'פּ', 'צּ' => 'צּ', 'קּ' => 'קּ', 'רּ' => 'רּ', 'שּ' => 'שּ', 'תּ' => 'תּ', 'וֹ' => 'וֹ', 'בֿ' => 'בֿ', 'כֿ' => 'כֿ', 'פֿ' => 'פֿ', '𑂚' => '𑂚', '𑂜' => '𑂜', '𑂫' => '𑂫', '𑄮' => '𑄮', '𑄯' => '𑄯', '𑍋' => '𑍋', '𑍌' => '𑍌', '𑒻' => '𑒻', '𑒼' => '𑒼', '𑒾' => '𑒾', '𑖺' => '𑖺', '𑖻' => '𑖻', '𑤸' => '𑤸', '𝅗𝅥' => '𝅗𝅥', '𝅘𝅥' => '𝅘𝅥', '𝅘𝅥𝅮' => '𝅘𝅥𝅮', '𝅘𝅥𝅯' => '𝅘𝅥𝅯', '𝅘𝅥𝅰' => '𝅘𝅥𝅰', '𝅘𝅥𝅱' => '𝅘𝅥𝅱', '𝅘𝅥𝅲' => '𝅘𝅥𝅲', '𝆹𝅥' => '𝆹𝅥', '𝆺𝅥' => '𝆺𝅥', '𝆹𝅥𝅮' => '𝆹𝅥𝅮', '𝆺𝅥𝅮' => '𝆺𝅥𝅮', '𝆹𝅥𝅯' => '𝆹𝅥𝅯', '𝆺𝅥𝅯' => '𝆺𝅥𝅯', '丽' => '丽', '丸' => '丸', '乁' => '乁', '𠄢' => '𠄢', '你' => '你', '侮' => '侮', '侻' => '侻', '倂' => '倂', '偺' => '偺', '備' => '備', '僧' => '僧', '像' => '像', '㒞' => '㒞', '𠘺' => '𠘺', '免' => '免', '兔' => '兔', '兤' => '兤', '具' => '具', '𠔜' => '𠔜', '㒹' => '㒹', '內' => '內', '再' => '再', '𠕋' => '𠕋', '冗' => '冗', '冤' => '冤', '仌' => '仌', '冬' => '冬', '况' => '况', '𩇟' => '𩇟', '凵' => '凵', '刃' => '刃', '㓟' => '㓟', '刻' => '刻', '剆' => '剆', '割' => '割', '剷' => '剷', '㔕' => '㔕', '勇' => '勇', '勉' => '勉', '勤' => '勤', '勺' => '勺', '包' => '包', '匆' => '匆', '北' => '北', '卉' => '卉', '卑' => '卑', '博' => '博', '即' => '即', '卽' => '卽', '卿' => '卿', '卿' => '卿', '卿' => '卿', '𠨬' => '𠨬', '灰' => '灰', '及' => '及', '叟' => '叟', '𠭣' => '𠭣', '叫' => '叫', '叱' => '叱', '吆' => '吆', '咞' => '咞', '吸' => '吸', '呈' => '呈', '周' => '周', '咢' => '咢', '哶' => '哶', '唐' => '唐', '啓' => '啓', '啣' => '啣', '善' => '善', '善' => '善', '喙' => '喙', '喫' => '喫', '喳' => '喳', '嗂' => '嗂', '圖' => '圖', '嘆' => '嘆', '圗' => '圗', '噑' => '噑', '噴' => '噴', '切' => '切', '壮' => '壮', '城' => '城', '埴' => '埴', '堍' => '堍', '型' => '型', '堲' => '堲', '報' => '報', '墬' => '墬', '𡓤' => '𡓤', '売' => '売', '壷' => '壷', '夆' => '夆', '多' => '多', '夢' => '夢', '奢' => '奢', '𡚨' => '𡚨', '𡛪' => '𡛪', '姬' => '姬', '娛' => '娛', '娧' => '娧', '姘' => '姘', '婦' => '婦', '㛮' => '㛮', '㛼' => '㛼', '嬈' => '嬈', '嬾' => '嬾', '嬾' => '嬾', '𡧈' => '𡧈', '寃' => '寃', '寘' => '寘', '寧' => '寧', '寳' => '寳', '𡬘' => '𡬘', '寿' => '寿', '将' => '将', '当' => '当', '尢' => '尢', '㞁' => '㞁', '屠' => '屠', '屮' => '屮', '峀' => '峀', '岍' => '岍', '𡷤' => '𡷤', '嵃' => '嵃', '𡷦' => '𡷦', '嵮' => '嵮', '嵫' => '嵫', '嵼' => '嵼', '巡' => '巡', '巢' => '巢', '㠯' => '㠯', '巽' => '巽', '帨' => '帨', '帽' => '帽', '幩' => '幩', '㡢' => '㡢', '𢆃' => '𢆃', '㡼' => '㡼', '庰' => '庰', '庳' => '庳', '庶' => '庶', '廊' => '廊', '𪎒' => '𪎒', '廾' => '廾', '𢌱' => '𢌱', '𢌱' => '𢌱', '舁' => '舁', '弢' => '弢', '弢' => '弢', '㣇' => '㣇', '𣊸' => '𣊸', '𦇚' => '𦇚', '形' => '形', '彫' => '彫', '㣣' => '㣣', '徚' => '徚', '忍' => '忍', '志' => '志', '忹' => '忹', '悁' => '悁', '㤺' => '㤺', '㤜' => '㤜', '悔' => '悔', '𢛔' => '𢛔', '惇' => '惇', '慈' => '慈', '慌' => '慌', '慎' => '慎', '慌' => '慌', '慺' => '慺', '憎' => '憎', '憲' => '憲', '憤' => '憤', '憯' => '憯', '懞' => '懞', '懲' => '懲', '懶' => '懶', '成' => '成', '戛' => '戛', '扝' => '扝', '抱' => '抱', '拔' => '拔', '捐' => '捐', '𢬌' => '𢬌', '挽' => '挽', '拼' => '拼', '捨' => '捨', '掃' => '掃', '揤' => '揤', '𢯱' => '𢯱', '搢' => '搢', '揅' => '揅', '掩' => '掩', '㨮' => '㨮', '摩' => '摩', '摾' => '摾', '撝' => '撝', '摷' => '摷', '㩬' => '㩬', '敏' => '敏', '敬' => '敬', '𣀊' => '𣀊', '旣' => '旣', '書' => '書', '晉' => '晉', '㬙' => '㬙', '暑' => '暑', '㬈' => '㬈', '㫤' => '㫤', '冒' => '冒', '冕' => '冕', '最' => '最', '暜' => '暜', '肭' => '肭', '䏙' => '䏙', '朗' => '朗', '望' => '望', '朡' => '朡', '杞' => '杞', '杓' => '杓', '𣏃' => '𣏃', '㭉' => '㭉', '柺' => '柺', '枅' => '枅', '桒' => '桒', '梅' => '梅', '𣑭' => '𣑭', '梎' => '梎', '栟' => '栟', '椔' => '椔', '㮝' => '㮝', '楂' => '楂', '榣' => '榣', '槪' => '槪', '檨' => '檨', '𣚣' => '𣚣', '櫛' => '櫛', '㰘' => '㰘', '次' => '次', '𣢧' => '𣢧', '歔' => '歔', '㱎' => '㱎', '歲' => '歲', '殟' => '殟', '殺' => '殺', '殻' => '殻', '𣪍' => '𣪍', '𡴋' => '𡴋', '𣫺' => '𣫺', '汎' => '汎', '𣲼' => '𣲼', '沿' => '沿', '泍' => '泍', '汧' => '汧', '洖' => '洖', '派' => '派', '海' => '海', '流' => '流', '浩' => '浩', '浸' => '浸', '涅' => '涅', '𣴞' => '𣴞', '洴' => '洴', '港' => '港', '湮' => '湮', '㴳' => '㴳', '滋' => '滋', '滇' => '滇', '𣻑' => '𣻑', '淹' => '淹', '潮' => '潮', '𣽞' => '𣽞', '𣾎' => '𣾎', '濆' => '濆', '瀹' => '瀹', '瀞' => '瀞', '瀛' => '瀛', '㶖' => '㶖', '灊' => '灊', '災' => '災', '灷' => '灷', '炭' => '炭', '𠔥' => '𠔥', '煅' => '煅', '𤉣' => '𤉣', '熜' => '熜', '𤎫' => '𤎫', '爨' => '爨', '爵' => '爵', '牐' => '牐', '𤘈' => '𤘈', '犀' => '犀', '犕' => '犕', '𤜵' => '𤜵', '𤠔' => '𤠔', '獺' => '獺', '王' => '王', '㺬' => '㺬', '玥' => '玥', '㺸' => '㺸', '㺸' => '㺸', '瑇' => '瑇', '瑜' => '瑜', '瑱' => '瑱', '璅' => '璅', '瓊' => '瓊', '㼛' => '㼛', '甤' => '甤', '𤰶' => '𤰶', '甾' => '甾', '𤲒' => '𤲒', '異' => '異', '𢆟' => '𢆟', '瘐' => '瘐', '𤾡' => '𤾡', '𤾸' => '𤾸', '𥁄' => '𥁄', '㿼' => '㿼', '䀈' => '䀈', '直' => '直', '𥃳' => '𥃳', '𥃲' => '𥃲', '𥄙' => '𥄙', '𥄳' => '𥄳', '眞' => '眞', '真' => '真', '真' => '真', '睊' => '睊', '䀹' => '䀹', '瞋' => '瞋', '䁆' => '䁆', '䂖' => '䂖', '𥐝' => '𥐝', '硎' => '硎', '碌' => '碌', '磌' => '磌', '䃣' => '䃣', '𥘦' => '𥘦', '祖' => '祖', '𥚚' => '𥚚', '𥛅' => '𥛅', '福' => '福', '秫' => '秫', '䄯' => '䄯', '穀' => '穀', '穊' => '穊', '穏' => '穏', '𥥼' => '𥥼', '𥪧' => '𥪧', '𥪧' => '𥪧', '竮' => '竮', '䈂' => '䈂', '𥮫' => '𥮫', '篆' => '篆', '築' => '築', '䈧' => '䈧', '𥲀' => '𥲀', '糒' => '糒', '䊠' => '䊠', '糨' => '糨', '糣' => '糣', '紀' => '紀', '𥾆' => '𥾆', '絣' => '絣', '䌁' => '䌁', '緇' => '緇', '縂' => '縂', '繅' => '繅', '䌴' => '䌴', '𦈨' => '𦈨', '𦉇' => '𦉇', '䍙' => '䍙', '𦋙' => '𦋙', '罺' => '罺', '𦌾' => '𦌾', '羕' => '羕', '翺' => '翺', '者' => '者', '𦓚' => '𦓚', '𦔣' => '𦔣', '聠' => '聠', '𦖨' => '𦖨', '聰' => '聰', '𣍟' => '𣍟', '䏕' => '䏕', '育' => '育', '脃' => '脃', '䐋' => '䐋', '脾' => '脾', '媵' => '媵', '𦞧' => '𦞧', '𦞵' => '𦞵', '𣎓' => '𣎓', '𣎜' => '𣎜', '舁' => '舁', '舄' => '舄', '辞' => '辞', '䑫' => '䑫', '芑' => '芑', '芋' => '芋', '芝' => '芝', '劳' => '劳', '花' => '花', '芳' => '芳', '芽' => '芽', '苦' => '苦', '𦬼' => '𦬼', '若' => '若', '茝' => '茝', '荣' => '荣', '莭' => '莭', '茣' => '茣', '莽' => '莽', '菧' => '菧', '著' => '著', '荓' => '荓', '菊' => '菊', '菌' => '菌', '菜' => '菜', '𦰶' => '𦰶', '𦵫' => '𦵫', '𦳕' => '𦳕', '䔫' => '䔫', '蓱' => '蓱', '蓳' => '蓳', '蔖' => '蔖', '𧏊' => '𧏊', '蕤' => '蕤', '𦼬' => '𦼬', '䕝' => '䕝', '䕡' => '䕡', '𦾱' => '𦾱', '𧃒' => '𧃒', '䕫' => '䕫', '虐' => '虐', '虜' => '虜', '虧' => '虧', '虩' => '虩', '蚩' => '蚩', '蚈' => '蚈', '蜎' => '蜎', '蛢' => '蛢', '蝹' => '蝹', '蜨' => '蜨', '蝫' => '蝫', '螆' => '螆', '䗗' => '䗗', '蟡' => '蟡', '蠁' => '蠁', '䗹' => '䗹', '衠' => '衠', '衣' => '衣', '𧙧' => '𧙧', '裗' => '裗', '裞' => '裞', '䘵' => '䘵', '裺' => '裺', '㒻' => '㒻', '𧢮' => '𧢮', '𧥦' => '𧥦', '䚾' => '䚾', '䛇' => '䛇', '誠' => '誠', '諭' => '諭', '變' => '變', '豕' => '豕', '𧲨' => '𧲨', '貫' => '貫', '賁' => '賁', '贛' => '贛', '起' => '起', '𧼯' => '𧼯', '𠠄' => '𠠄', '跋' => '跋', '趼' => '趼', '跰' => '跰', '𠣞' => '𠣞', '軔' => '軔', '輸' => '輸', '𨗒' => '𨗒', '𨗭' => '𨗭', '邔' => '邔', '郱' => '郱', '鄑' => '鄑', '𨜮' => '𨜮', '鄛' => '鄛', '鈸' => '鈸', '鋗' => '鋗', '鋘' => '鋘', '鉼' => '鉼', '鏹' => '鏹', '鐕' => '鐕', '𨯺' => '𨯺', '開' => '開', '䦕' => '䦕', '閷' => '閷', '𨵷' => '𨵷', '䧦' => '䧦', '雃' => '雃', '嶲' => '嶲', '霣' => '霣', '𩅅' => '𩅅', '𩈚' => '𩈚', '䩮' => '䩮', '䩶' => '䩶', '韠' => '韠', '𩐊' => '𩐊', '䪲' => '䪲', '𩒖' => '𩒖', '頋' => '頋', '頋' => '頋', '頩' => '頩', '𩖶' => '𩖶', '飢' => '飢', '䬳' => '䬳', '餩' => '餩', '馧' => '馧', '駂' => '駂', '駾' => '駾', '䯎' => '䯎', '𩬰' => '𩬰', '鬒' => '鬒', '鱀' => '鱀', '鳽' => '鳽', '䳎' => '䳎', '䳭' => '䳭', '鵧' => '鵧', '𪃎' => '𪃎', '䳸' => '䳸', '𪄅' => '𪄅', '𪈎' => '𪈎', '𪊑' => '𪊑', '麻' => '麻', '䵖' => '䵖', '黹' => '黹', '黾' => '黾', '鼅' => '鼅', '鼏' => '鼏', '鼖' => '鼖', '鼻' => '鼻', '𪘀' => '𪘀'); diff --git a/vendor-bundle/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php b/vendor-bundle/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php new file mode 100644 index 000000000..8b17b3767 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php @@ -0,0 +1,5 @@ + 230, '́' => 230, '̂' => 230, '̃' => 230, '̄' => 230, '̅' => 230, '̆' => 230, '̇' => 230, '̈' => 230, '̉' => 230, '̊' => 230, '̋' => 230, '̌' => 230, '̍' => 230, '̎' => 230, '̏' => 230, '̐' => 230, '̑' => 230, '̒' => 230, '̓' => 230, '̔' => 230, '̕' => 232, '̖' => 220, '̗' => 220, '̘' => 220, '̙' => 220, '̚' => 232, '̛' => 216, '̜' => 220, '̝' => 220, '̞' => 220, '̟' => 220, '̠' => 220, '̡' => 202, '̢' => 202, '̣' => 220, '̤' => 220, '̥' => 220, '̦' => 220, '̧' => 202, '̨' => 202, '̩' => 220, '̪' => 220, '̫' => 220, '̬' => 220, '̭' => 220, '̮' => 220, '̯' => 220, '̰' => 220, '̱' => 220, '̲' => 220, '̳' => 220, '̴' => 1, '̵' => 1, '̶' => 1, '̷' => 1, '̸' => 1, '̹' => 220, '̺' => 220, '̻' => 220, '̼' => 220, '̽' => 230, '̾' => 230, '̿' => 230, '̀' => 230, '́' => 230, '͂' => 230, '̓' => 230, '̈́' => 230, 'ͅ' => 240, '͆' => 230, '͇' => 220, '͈' => 220, '͉' => 220, '͊' => 230, '͋' => 230, '͌' => 230, '͍' => 220, '͎' => 220, '͐' => 230, '͑' => 230, '͒' => 230, '͓' => 220, '͔' => 220, '͕' => 220, '͖' => 220, '͗' => 230, '͘' => 232, '͙' => 220, '͚' => 220, '͛' => 230, '͜' => 233, '͝' => 234, '͞' => 234, '͟' => 233, '͠' => 234, '͡' => 234, '͢' => 233, 'ͣ' => 230, 'ͤ' => 230, 'ͥ' => 230, 'ͦ' => 230, 'ͧ' => 230, 'ͨ' => 230, 'ͩ' => 230, 'ͪ' => 230, 'ͫ' => 230, 'ͬ' => 230, 'ͭ' => 230, 'ͮ' => 230, 'ͯ' => 230, '҃' => 230, '҄' => 230, '҅' => 230, '҆' => 230, '҇' => 230, '֑' => 220, '֒' => 230, '֓' => 230, '֔' => 230, '֕' => 230, '֖' => 220, '֗' => 230, '֘' => 230, '֙' => 230, '֚' => 222, '֛' => 220, '֜' => 230, '֝' => 230, '֞' => 230, '֟' => 230, '֠' => 230, '֡' => 230, '֢' => 220, '֣' => 220, '֤' => 220, '֥' => 220, '֦' => 220, '֧' => 220, '֨' => 230, '֩' => 230, '֪' => 220, '֫' => 230, '֬' => 230, '֭' => 222, '֮' => 228, '֯' => 230, 'ְ' => 10, 'ֱ' => 11, 'ֲ' => 12, 'ֳ' => 13, 'ִ' => 14, 'ֵ' => 15, 'ֶ' => 16, 'ַ' => 17, 'ָ' => 18, 'ֹ' => 19, 'ֺ' => 19, 'ֻ' => 20, 'ּ' => 21, 'ֽ' => 22, 'ֿ' => 23, 'ׁ' => 24, 'ׂ' => 25, 'ׄ' => 230, 'ׅ' => 220, 'ׇ' => 18, 'ؐ' => 230, 'ؑ' => 230, 'ؒ' => 230, 'ؓ' => 230, 'ؔ' => 230, 'ؕ' => 230, 'ؖ' => 230, 'ؗ' => 230, 'ؘ' => 30, 'ؙ' => 31, 'ؚ' => 32, 'ً' => 27, 'ٌ' => 28, 'ٍ' => 29, 'َ' => 30, 'ُ' => 31, 'ِ' => 32, 'ّ' => 33, 'ْ' => 34, 'ٓ' => 230, 'ٔ' => 230, 'ٕ' => 220, 'ٖ' => 220, 'ٗ' => 230, '٘' => 230, 'ٙ' => 230, 'ٚ' => 230, 'ٛ' => 230, 'ٜ' => 220, 'ٝ' => 230, 'ٞ' => 230, 'ٟ' => 220, 'ٰ' => 35, 'ۖ' => 230, 'ۗ' => 230, 'ۘ' => 230, 'ۙ' => 230, 'ۚ' => 230, 'ۛ' => 230, 'ۜ' => 230, '۟' => 230, '۠' => 230, 'ۡ' => 230, 'ۢ' => 230, 'ۣ' => 220, 'ۤ' => 230, 'ۧ' => 230, 'ۨ' => 230, '۪' => 220, '۫' => 230, '۬' => 230, 'ۭ' => 220, 'ܑ' => 36, 'ܰ' => 230, 'ܱ' => 220, 'ܲ' => 230, 'ܳ' => 230, 'ܴ' => 220, 'ܵ' => 230, 'ܶ' => 230, 'ܷ' => 220, 'ܸ' => 220, 'ܹ' => 220, 'ܺ' => 230, 'ܻ' => 220, 'ܼ' => 220, 'ܽ' => 230, 'ܾ' => 220, 'ܿ' => 230, '݀' => 230, '݁' => 230, '݂' => 220, '݃' => 230, '݄' => 220, '݅' => 230, '݆' => 220, '݇' => 230, '݈' => 220, '݉' => 230, '݊' => 230, '߫' => 230, '߬' => 230, '߭' => 230, '߮' => 230, '߯' => 230, '߰' => 230, '߱' => 230, '߲' => 220, '߳' => 230, '߽' => 220, 'ࠖ' => 230, 'ࠗ' => 230, '࠘' => 230, '࠙' => 230, 'ࠛ' => 230, 'ࠜ' => 230, 'ࠝ' => 230, 'ࠞ' => 230, 'ࠟ' => 230, 'ࠠ' => 230, 'ࠡ' => 230, 'ࠢ' => 230, 'ࠣ' => 230, 'ࠥ' => 230, 'ࠦ' => 230, 'ࠧ' => 230, 'ࠩ' => 230, 'ࠪ' => 230, 'ࠫ' => 230, 'ࠬ' => 230, '࠭' => 230, '࡙' => 220, '࡚' => 220, '࡛' => 220, '࣓' => 220, 'ࣔ' => 230, 'ࣕ' => 230, 'ࣖ' => 230, 'ࣗ' => 230, 'ࣘ' => 230, 'ࣙ' => 230, 'ࣚ' => 230, 'ࣛ' => 230, 'ࣜ' => 230, 'ࣝ' => 230, 'ࣞ' => 230, 'ࣟ' => 230, '࣠' => 230, '࣡' => 230, 'ࣣ' => 220, 'ࣤ' => 230, 'ࣥ' => 230, 'ࣦ' => 220, 'ࣧ' => 230, 'ࣨ' => 230, 'ࣩ' => 220, '࣪' => 230, '࣫' => 230, '࣬' => 230, '࣭' => 220, '࣮' => 220, '࣯' => 220, 'ࣰ' => 27, 'ࣱ' => 28, 'ࣲ' => 29, 'ࣳ' => 230, 'ࣴ' => 230, 'ࣵ' => 230, 'ࣶ' => 220, 'ࣷ' => 230, 'ࣸ' => 230, 'ࣹ' => 220, 'ࣺ' => 220, 'ࣻ' => 230, 'ࣼ' => 230, 'ࣽ' => 230, 'ࣾ' => 230, 'ࣿ' => 230, '़' => 7, '्' => 9, '॑' => 230, '॒' => 220, '॓' => 230, '॔' => 230, '়' => 7, '্' => 9, '৾' => 230, '਼' => 7, '੍' => 9, '઼' => 7, '્' => 9, '଼' => 7, '୍' => 9, '்' => 9, '్' => 9, 'ౕ' => 84, 'ౖ' => 91, '಼' => 7, '್' => 9, '഻' => 9, '഼' => 9, '്' => 9, '්' => 9, 'ุ' => 103, 'ู' => 103, 'ฺ' => 9, '่' => 107, '้' => 107, '๊' => 107, '๋' => 107, 'ຸ' => 118, 'ູ' => 118, '຺' => 9, '່' => 122, '້' => 122, '໊' => 122, '໋' => 122, '༘' => 220, '༙' => 220, '༵' => 220, '༷' => 220, '༹' => 216, 'ཱ' => 129, 'ི' => 130, 'ུ' => 132, 'ེ' => 130, 'ཻ' => 130, 'ོ' => 130, 'ཽ' => 130, 'ྀ' => 130, 'ྂ' => 230, 'ྃ' => 230, '྄' => 9, '྆' => 230, '྇' => 230, '࿆' => 220, '့' => 7, '္' => 9, '်' => 9, 'ႍ' => 220, '፝' => 230, '፞' => 230, '፟' => 230, '᜔' => 9, '᜴' => 9, '្' => 9, '៝' => 230, 'ᢩ' => 228, '᤹' => 222, '᤺' => 230, '᤻' => 220, 'ᨗ' => 230, 'ᨘ' => 220, '᩠' => 9, '᩵' => 230, '᩶' => 230, '᩷' => 230, '᩸' => 230, '᩹' => 230, '᩺' => 230, '᩻' => 230, '᩼' => 230, '᩿' => 220, '᪰' => 230, '᪱' => 230, '᪲' => 230, '᪳' => 230, '᪴' => 230, '᪵' => 220, '᪶' => 220, '᪷' => 220, '᪸' => 220, '᪹' => 220, '᪺' => 220, '᪻' => 230, '᪼' => 230, '᪽' => 220, 'ᪿ' => 220, 'ᫀ' => 220, '᬴' => 7, '᭄' => 9, '᭫' => 230, '᭬' => 220, '᭭' => 230, '᭮' => 230, '᭯' => 230, '᭰' => 230, '᭱' => 230, '᭲' => 230, '᭳' => 230, '᮪' => 9, '᮫' => 9, '᯦' => 7, '᯲' => 9, '᯳' => 9, '᰷' => 7, '᳐' => 230, '᳑' => 230, '᳒' => 230, '᳔' => 1, '᳕' => 220, '᳖' => 220, '᳗' => 220, '᳘' => 220, '᳙' => 220, '᳚' => 230, '᳛' => 230, '᳜' => 220, '᳝' => 220, '᳞' => 220, '᳟' => 220, '᳠' => 230, '᳢' => 1, '᳣' => 1, '᳤' => 1, '᳥' => 1, '᳦' => 1, '᳧' => 1, '᳨' => 1, '᳭' => 220, '᳴' => 230, '᳸' => 230, '᳹' => 230, '᷀' => 230, '᷁' => 230, '᷂' => 220, '᷃' => 230, '᷄' => 230, '᷅' => 230, '᷆' => 230, '᷇' => 230, '᷈' => 230, '᷉' => 230, '᷊' => 220, '᷋' => 230, '᷌' => 230, '᷍' => 234, '᷎' => 214, '᷏' => 220, '᷐' => 202, '᷑' => 230, '᷒' => 230, 'ᷓ' => 230, 'ᷔ' => 230, 'ᷕ' => 230, 'ᷖ' => 230, 'ᷗ' => 230, 'ᷘ' => 230, 'ᷙ' => 230, 'ᷚ' => 230, 'ᷛ' => 230, 'ᷜ' => 230, 'ᷝ' => 230, 'ᷞ' => 230, 'ᷟ' => 230, 'ᷠ' => 230, 'ᷡ' => 230, 'ᷢ' => 230, 'ᷣ' => 230, 'ᷤ' => 230, 'ᷥ' => 230, 'ᷦ' => 230, 'ᷧ' => 230, 'ᷨ' => 230, 'ᷩ' => 230, 'ᷪ' => 230, 'ᷫ' => 230, 'ᷬ' => 230, 'ᷭ' => 230, 'ᷮ' => 230, 'ᷯ' => 230, 'ᷰ' => 230, 'ᷱ' => 230, 'ᷲ' => 230, 'ᷳ' => 230, 'ᷴ' => 230, '᷵' => 230, '᷶' => 232, '᷷' => 228, '᷸' => 228, '᷹' => 220, '᷻' => 230, '᷼' => 233, '᷽' => 220, '᷾' => 230, '᷿' => 220, '⃐' => 230, '⃑' => 230, '⃒' => 1, '⃓' => 1, '⃔' => 230, '⃕' => 230, '⃖' => 230, '⃗' => 230, '⃘' => 1, '⃙' => 1, '⃚' => 1, '⃛' => 230, '⃜' => 230, '⃡' => 230, '⃥' => 1, '⃦' => 1, '⃧' => 230, '⃨' => 220, '⃩' => 230, '⃪' => 1, '⃫' => 1, '⃬' => 220, '⃭' => 220, '⃮' => 220, '⃯' => 220, '⃰' => 230, '⳯' => 230, '⳰' => 230, '⳱' => 230, '⵿' => 9, 'ⷠ' => 230, 'ⷡ' => 230, 'ⷢ' => 230, 'ⷣ' => 230, 'ⷤ' => 230, 'ⷥ' => 230, 'ⷦ' => 230, 'ⷧ' => 230, 'ⷨ' => 230, 'ⷩ' => 230, 'ⷪ' => 230, 'ⷫ' => 230, 'ⷬ' => 230, 'ⷭ' => 230, 'ⷮ' => 230, 'ⷯ' => 230, 'ⷰ' => 230, 'ⷱ' => 230, 'ⷲ' => 230, 'ⷳ' => 230, 'ⷴ' => 230, 'ⷵ' => 230, 'ⷶ' => 230, 'ⷷ' => 230, 'ⷸ' => 230, 'ⷹ' => 230, 'ⷺ' => 230, 'ⷻ' => 230, 'ⷼ' => 230, 'ⷽ' => 230, 'ⷾ' => 230, 'ⷿ' => 230, '〪' => 218, '〫' => 228, '〬' => 232, '〭' => 222, '〮' => 224, '〯' => 224, '゙' => 8, '゚' => 8, '꙯' => 230, 'ꙴ' => 230, 'ꙵ' => 230, 'ꙶ' => 230, 'ꙷ' => 230, 'ꙸ' => 230, 'ꙹ' => 230, 'ꙺ' => 230, 'ꙻ' => 230, '꙼' => 230, '꙽' => 230, 'ꚞ' => 230, 'ꚟ' => 230, '꛰' => 230, '꛱' => 230, '꠆' => 9, '꠬' => 9, '꣄' => 9, '꣠' => 230, '꣡' => 230, '꣢' => 230, '꣣' => 230, '꣤' => 230, '꣥' => 230, '꣦' => 230, '꣧' => 230, '꣨' => 230, '꣩' => 230, '꣪' => 230, '꣫' => 230, '꣬' => 230, '꣭' => 230, '꣮' => 230, '꣯' => 230, '꣰' => 230, '꣱' => 230, '꤫' => 220, '꤬' => 220, '꤭' => 220, '꥓' => 9, '꦳' => 7, '꧀' => 9, 'ꪰ' => 230, 'ꪲ' => 230, 'ꪳ' => 230, 'ꪴ' => 220, 'ꪷ' => 230, 'ꪸ' => 230, 'ꪾ' => 230, '꪿' => 230, '꫁' => 230, '꫶' => 9, '꯭' => 9, 'ﬞ' => 26, '︠' => 230, '︡' => 230, '︢' => 230, '︣' => 230, '︤' => 230, '︥' => 230, '︦' => 230, '︧' => 220, '︨' => 220, '︩' => 220, '︪' => 220, '︫' => 220, '︬' => 220, '︭' => 220, '︮' => 230, '︯' => 230, '𐇽' => 220, '𐋠' => 220, '𐍶' => 230, '𐍷' => 230, '𐍸' => 230, '𐍹' => 230, '𐍺' => 230, '𐨍' => 220, '𐨏' => 230, '𐨸' => 230, '𐨹' => 1, '𐨺' => 220, '𐨿' => 9, '𐫥' => 230, '𐫦' => 220, '𐴤' => 230, '𐴥' => 230, '𐴦' => 230, '𐴧' => 230, '𐺫' => 230, '𐺬' => 230, '𐽆' => 220, '𐽇' => 220, '𐽈' => 230, '𐽉' => 230, '𐽊' => 230, '𐽋' => 220, '𐽌' => 230, '𐽍' => 220, '𐽎' => 220, '𐽏' => 220, '𐽐' => 220, '𑁆' => 9, '𑁿' => 9, '𑂹' => 9, '𑂺' => 7, '𑄀' => 230, '𑄁' => 230, '𑄂' => 230, '𑄳' => 9, '𑄴' => 9, '𑅳' => 7, '𑇀' => 9, '𑇊' => 7, '𑈵' => 9, '𑈶' => 7, '𑋩' => 7, '𑋪' => 9, '𑌻' => 7, '𑌼' => 7, '𑍍' => 9, '𑍦' => 230, '𑍧' => 230, '𑍨' => 230, '𑍩' => 230, '𑍪' => 230, '𑍫' => 230, '𑍬' => 230, '𑍰' => 230, '𑍱' => 230, '𑍲' => 230, '𑍳' => 230, '𑍴' => 230, '𑑂' => 9, '𑑆' => 7, '𑑞' => 230, '𑓂' => 9, '𑓃' => 7, '𑖿' => 9, '𑗀' => 7, '𑘿' => 9, '𑚶' => 9, '𑚷' => 7, '𑜫' => 9, '𑠹' => 9, '𑠺' => 7, '𑤽' => 9, '𑤾' => 9, '𑥃' => 7, '𑧠' => 9, '𑨴' => 9, '𑩇' => 9, '𑪙' => 9, '𑰿' => 9, '𑵂' => 7, '𑵄' => 9, '𑵅' => 9, '𑶗' => 9, '𖫰' => 1, '𖫱' => 1, '𖫲' => 1, '𖫳' => 1, '𖫴' => 1, '𖬰' => 230, '𖬱' => 230, '𖬲' => 230, '𖬳' => 230, '𖬴' => 230, '𖬵' => 230, '𖬶' => 230, '𖿰' => 6, '𖿱' => 6, '𛲞' => 1, '𝅥' => 216, '𝅦' => 216, '𝅧' => 1, '𝅨' => 1, '𝅩' => 1, '𝅭' => 226, '𝅮' => 216, '𝅯' => 216, '𝅰' => 216, '𝅱' => 216, '𝅲' => 216, '𝅻' => 220, '𝅼' => 220, '𝅽' => 220, '𝅾' => 220, '𝅿' => 220, '𝆀' => 220, '𝆁' => 220, '𝆂' => 220, '𝆅' => 230, '𝆆' => 230, '𝆇' => 230, '𝆈' => 230, '𝆉' => 230, '𝆊' => 220, '𝆋' => 220, '𝆪' => 230, '𝆫' => 230, '𝆬' => 230, '𝆭' => 230, '𝉂' => 230, '𝉃' => 230, '𝉄' => 230, '𞀀' => 230, '𞀁' => 230, '𞀂' => 230, '𞀃' => 230, '𞀄' => 230, '𞀅' => 230, '𞀆' => 230, '𞀈' => 230, '𞀉' => 230, '𞀊' => 230, '𞀋' => 230, '𞀌' => 230, '𞀍' => 230, '𞀎' => 230, '𞀏' => 230, '𞀐' => 230, '𞀑' => 230, '𞀒' => 230, '𞀓' => 230, '𞀔' => 230, '𞀕' => 230, '𞀖' => 230, '𞀗' => 230, '𞀘' => 230, '𞀛' => 230, '𞀜' => 230, '𞀝' => 230, '𞀞' => 230, '𞀟' => 230, '𞀠' => 230, '𞀡' => 230, '𞀣' => 230, '𞀤' => 230, '𞀦' => 230, '𞀧' => 230, '𞀨' => 230, '𞀩' => 230, '𞀪' => 230, '𞄰' => 230, '𞄱' => 230, '𞄲' => 230, '𞄳' => 230, '𞄴' => 230, '𞄵' => 230, '𞄶' => 230, '𞋬' => 230, '𞋭' => 230, '𞋮' => 230, '𞋯' => 230, '𞣐' => 220, '𞣑' => 220, '𞣒' => 220, '𞣓' => 220, '𞣔' => 220, '𞣕' => 220, '𞣖' => 220, '𞥄' => 230, '𞥅' => 230, '𞥆' => 230, '𞥇' => 230, '𞥈' => 230, '𞥉' => 230, '𞥊' => 7); diff --git a/vendor-bundle/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php b/vendor-bundle/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php new file mode 100644 index 000000000..d631c4d5f --- /dev/null +++ b/vendor-bundle/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php @@ -0,0 +1,5 @@ + ' ', '¨' => ' ̈', 'ª' => 'a', '¯' => ' ̄', '²' => '2', '³' => '3', '´' => ' ́', 'µ' => 'μ', '¸' => ' ̧', '¹' => '1', 'º' => 'o', '¼' => '1⁄4', '½' => '1⁄2', '¾' => '3⁄4', 'IJ' => 'IJ', 'ij' => 'ij', 'Ŀ' => 'L·', 'ŀ' => 'l·', 'ʼn' => 'ʼn', 'ſ' => 's', 'DŽ' => 'DŽ', 'Dž' => 'Dž', 'dž' => 'dž', 'LJ' => 'LJ', 'Lj' => 'Lj', 'lj' => 'lj', 'NJ' => 'NJ', 'Nj' => 'Nj', 'nj' => 'nj', 'DZ' => 'DZ', 'Dz' => 'Dz', 'dz' => 'dz', 'ʰ' => 'h', 'ʱ' => 'ɦ', 'ʲ' => 'j', 'ʳ' => 'r', 'ʴ' => 'ɹ', 'ʵ' => 'ɻ', 'ʶ' => 'ʁ', 'ʷ' => 'w', 'ʸ' => 'y', '˘' => ' ̆', '˙' => ' ̇', '˚' => ' ̊', '˛' => ' ̨', '˜' => ' ̃', '˝' => ' ̋', 'ˠ' => 'ɣ', 'ˡ' => 'l', 'ˢ' => 's', 'ˣ' => 'x', 'ˤ' => 'ʕ', 'ͺ' => ' ͅ', '΄' => ' ́', '΅' => ' ̈́', 'ϐ' => 'β', 'ϑ' => 'θ', 'ϒ' => 'Υ', 'ϓ' => 'Ύ', 'ϔ' => 'Ϋ', 'ϕ' => 'φ', 'ϖ' => 'π', 'ϰ' => 'κ', 'ϱ' => 'ρ', 'ϲ' => 'ς', 'ϴ' => 'Θ', 'ϵ' => 'ε', 'Ϲ' => 'Σ', 'և' => 'եւ', 'ٵ' => 'اٴ', 'ٶ' => 'وٴ', 'ٷ' => 'ۇٴ', 'ٸ' => 'يٴ', 'ำ' => 'ํา', 'ຳ' => 'ໍາ', 'ໜ' => 'ຫນ', 'ໝ' => 'ຫມ', '༌' => '་', 'ཷ' => 'ྲཱྀ', 'ཹ' => 'ླཱྀ', 'ჼ' => 'ნ', 'ᴬ' => 'A', 'ᴭ' => 'Æ', 'ᴮ' => 'B', 'ᴰ' => 'D', 'ᴱ' => 'E', 'ᴲ' => 'Ǝ', 'ᴳ' => 'G', 'ᴴ' => 'H', 'ᴵ' => 'I', 'ᴶ' => 'J', 'ᴷ' => 'K', 'ᴸ' => 'L', 'ᴹ' => 'M', 'ᴺ' => 'N', 'ᴼ' => 'O', 'ᴽ' => 'Ȣ', 'ᴾ' => 'P', 'ᴿ' => 'R', 'ᵀ' => 'T', 'ᵁ' => 'U', 'ᵂ' => 'W', 'ᵃ' => 'a', 'ᵄ' => 'ɐ', 'ᵅ' => 'ɑ', 'ᵆ' => 'ᴂ', 'ᵇ' => 'b', 'ᵈ' => 'd', 'ᵉ' => 'e', 'ᵊ' => 'ə', 'ᵋ' => 'ɛ', 'ᵌ' => 'ɜ', 'ᵍ' => 'g', 'ᵏ' => 'k', 'ᵐ' => 'm', 'ᵑ' => 'ŋ', 'ᵒ' => 'o', 'ᵓ' => 'ɔ', 'ᵔ' => 'ᴖ', 'ᵕ' => 'ᴗ', 'ᵖ' => 'p', 'ᵗ' => 't', 'ᵘ' => 'u', 'ᵙ' => 'ᴝ', 'ᵚ' => 'ɯ', 'ᵛ' => 'v', 'ᵜ' => 'ᴥ', 'ᵝ' => 'β', 'ᵞ' => 'γ', 'ᵟ' => 'δ', 'ᵠ' => 'φ', 'ᵡ' => 'χ', 'ᵢ' => 'i', 'ᵣ' => 'r', 'ᵤ' => 'u', 'ᵥ' => 'v', 'ᵦ' => 'β', 'ᵧ' => 'γ', 'ᵨ' => 'ρ', 'ᵩ' => 'φ', 'ᵪ' => 'χ', 'ᵸ' => 'н', 'ᶛ' => 'ɒ', 'ᶜ' => 'c', 'ᶝ' => 'ɕ', 'ᶞ' => 'ð', 'ᶟ' => 'ɜ', 'ᶠ' => 'f', 'ᶡ' => 'ɟ', 'ᶢ' => 'ɡ', 'ᶣ' => 'ɥ', 'ᶤ' => 'ɨ', 'ᶥ' => 'ɩ', 'ᶦ' => 'ɪ', 'ᶧ' => 'ᵻ', 'ᶨ' => 'ʝ', 'ᶩ' => 'ɭ', 'ᶪ' => 'ᶅ', 'ᶫ' => 'ʟ', 'ᶬ' => 'ɱ', 'ᶭ' => 'ɰ', 'ᶮ' => 'ɲ', 'ᶯ' => 'ɳ', 'ᶰ' => 'ɴ', 'ᶱ' => 'ɵ', 'ᶲ' => 'ɸ', 'ᶳ' => 'ʂ', 'ᶴ' => 'ʃ', 'ᶵ' => 'ƫ', 'ᶶ' => 'ʉ', 'ᶷ' => 'ʊ', 'ᶸ' => 'ᴜ', 'ᶹ' => 'ʋ', 'ᶺ' => 'ʌ', 'ᶻ' => 'z', 'ᶼ' => 'ʐ', 'ᶽ' => 'ʑ', 'ᶾ' => 'ʒ', 'ᶿ' => 'θ', 'ẚ' => 'aʾ', 'ẛ' => 'ṡ', '᾽' => ' ̓', '᾿' => ' ̓', '῀' => ' ͂', '῁' => ' ̈͂', '῍' => ' ̓̀', '῎' => ' ̓́', '῏' => ' ̓͂', '῝' => ' ̔̀', '῞' => ' ̔́', '῟' => ' ̔͂', '῭' => ' ̈̀', '΅' => ' ̈́', '´' => ' ́', '῾' => ' ̔', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', ' ' => ' ', '‑' => '‐', '‗' => ' ̳', '․' => '.', '‥' => '..', '…' => '...', ' ' => ' ', '″' => '′′', '‴' => '′′′', '‶' => '‵‵', '‷' => '‵‵‵', '‼' => '!!', '‾' => ' ̅', '⁇' => '??', '⁈' => '?!', '⁉' => '!?', '⁗' => '′′′′', ' ' => ' ', '⁰' => '0', 'ⁱ' => 'i', '⁴' => '4', '⁵' => '5', '⁶' => '6', '⁷' => '7', '⁸' => '8', '⁹' => '9', '⁺' => '+', '⁻' => '−', '⁼' => '=', '⁽' => '(', '⁾' => ')', 'ⁿ' => 'n', '₀' => '0', '₁' => '1', '₂' => '2', '₃' => '3', '₄' => '4', '₅' => '5', '₆' => '6', '₇' => '7', '₈' => '8', '₉' => '9', '₊' => '+', '₋' => '−', '₌' => '=', '₍' => '(', '₎' => ')', 'ₐ' => 'a', 'ₑ' => 'e', 'ₒ' => 'o', 'ₓ' => 'x', 'ₔ' => 'ə', 'ₕ' => 'h', 'ₖ' => 'k', 'ₗ' => 'l', 'ₘ' => 'm', 'ₙ' => 'n', 'ₚ' => 'p', 'ₛ' => 's', 'ₜ' => 't', '₨' => 'Rs', '℀' => 'a/c', '℁' => 'a/s', 'ℂ' => 'C', '℃' => '°C', '℅' => 'c/o', '℆' => 'c/u', 'ℇ' => 'Ɛ', '℉' => '°F', 'ℊ' => 'g', 'ℋ' => 'H', 'ℌ' => 'H', 'ℍ' => 'H', 'ℎ' => 'h', 'ℏ' => 'ħ', 'ℐ' => 'I', 'ℑ' => 'I', 'ℒ' => 'L', 'ℓ' => 'l', 'ℕ' => 'N', '№' => 'No', 'ℙ' => 'P', 'ℚ' => 'Q', 'ℛ' => 'R', 'ℜ' => 'R', 'ℝ' => 'R', '℠' => 'SM', '℡' => 'TEL', '™' => 'TM', 'ℤ' => 'Z', 'ℨ' => 'Z', 'ℬ' => 'B', 'ℭ' => 'C', 'ℯ' => 'e', 'ℰ' => 'E', 'ℱ' => 'F', 'ℳ' => 'M', 'ℴ' => 'o', 'ℵ' => 'א', 'ℶ' => 'ב', 'ℷ' => 'ג', 'ℸ' => 'ד', 'ℹ' => 'i', '℻' => 'FAX', 'ℼ' => 'π', 'ℽ' => 'γ', 'ℾ' => 'Γ', 'ℿ' => 'Π', '⅀' => '∑', 'ⅅ' => 'D', 'ⅆ' => 'd', 'ⅇ' => 'e', 'ⅈ' => 'i', 'ⅉ' => 'j', '⅐' => '1⁄7', '⅑' => '1⁄9', '⅒' => '1⁄10', '⅓' => '1⁄3', '⅔' => '2⁄3', '⅕' => '1⁄5', '⅖' => '2⁄5', '⅗' => '3⁄5', '⅘' => '4⁄5', '⅙' => '1⁄6', '⅚' => '5⁄6', '⅛' => '1⁄8', '⅜' => '3⁄8', '⅝' => '5⁄8', '⅞' => '7⁄8', '⅟' => '1⁄', 'Ⅰ' => 'I', 'Ⅱ' => 'II', 'Ⅲ' => 'III', 'Ⅳ' => 'IV', 'Ⅴ' => 'V', 'Ⅵ' => 'VI', 'Ⅶ' => 'VII', 'Ⅷ' => 'VIII', 'Ⅸ' => 'IX', 'Ⅹ' => 'X', 'Ⅺ' => 'XI', 'Ⅻ' => 'XII', 'Ⅼ' => 'L', 'Ⅽ' => 'C', 'Ⅾ' => 'D', 'Ⅿ' => 'M', 'ⅰ' => 'i', 'ⅱ' => 'ii', 'ⅲ' => 'iii', 'ⅳ' => 'iv', 'ⅴ' => 'v', 'ⅵ' => 'vi', 'ⅶ' => 'vii', 'ⅷ' => 'viii', 'ⅸ' => 'ix', 'ⅹ' => 'x', 'ⅺ' => 'xi', 'ⅻ' => 'xii', 'ⅼ' => 'l', 'ⅽ' => 'c', 'ⅾ' => 'd', 'ⅿ' => 'm', '↉' => '0⁄3', '∬' => '∫∫', '∭' => '∫∫∫', '∯' => '∮∮', '∰' => '∮∮∮', '①' => '1', '②' => '2', '③' => '3', '④' => '4', '⑤' => '5', '⑥' => '6', '⑦' => '7', '⑧' => '8', '⑨' => '9', '⑩' => '10', '⑪' => '11', '⑫' => '12', '⑬' => '13', '⑭' => '14', '⑮' => '15', '⑯' => '16', '⑰' => '17', '⑱' => '18', '⑲' => '19', '⑳' => '20', '⑴' => '(1)', '⑵' => '(2)', '⑶' => '(3)', '⑷' => '(4)', '⑸' => '(5)', '⑹' => '(6)', '⑺' => '(7)', '⑻' => '(8)', '⑼' => '(9)', '⑽' => '(10)', '⑾' => '(11)', '⑿' => '(12)', '⒀' => '(13)', '⒁' => '(14)', '⒂' => '(15)', '⒃' => '(16)', '⒄' => '(17)', '⒅' => '(18)', '⒆' => '(19)', '⒇' => '(20)', '⒈' => '1.', '⒉' => '2.', '⒊' => '3.', '⒋' => '4.', '⒌' => '5.', '⒍' => '6.', '⒎' => '7.', '⒏' => '8.', '⒐' => '9.', '⒑' => '10.', '⒒' => '11.', '⒓' => '12.', '⒔' => '13.', '⒕' => '14.', '⒖' => '15.', '⒗' => '16.', '⒘' => '17.', '⒙' => '18.', '⒚' => '19.', '⒛' => '20.', '⒜' => '(a)', '⒝' => '(b)', '⒞' => '(c)', '⒟' => '(d)', '⒠' => '(e)', '⒡' => '(f)', '⒢' => '(g)', '⒣' => '(h)', '⒤' => '(i)', '⒥' => '(j)', '⒦' => '(k)', '⒧' => '(l)', '⒨' => '(m)', '⒩' => '(n)', '⒪' => '(o)', '⒫' => '(p)', '⒬' => '(q)', '⒭' => '(r)', '⒮' => '(s)', '⒯' => '(t)', '⒰' => '(u)', '⒱' => '(v)', '⒲' => '(w)', '⒳' => '(x)', '⒴' => '(y)', '⒵' => '(z)', 'Ⓐ' => 'A', 'Ⓑ' => 'B', 'Ⓒ' => 'C', 'Ⓓ' => 'D', 'Ⓔ' => 'E', 'Ⓕ' => 'F', 'Ⓖ' => 'G', 'Ⓗ' => 'H', 'Ⓘ' => 'I', 'Ⓙ' => 'J', 'Ⓚ' => 'K', 'Ⓛ' => 'L', 'Ⓜ' => 'M', 'Ⓝ' => 'N', 'Ⓞ' => 'O', 'Ⓟ' => 'P', 'Ⓠ' => 'Q', 'Ⓡ' => 'R', 'Ⓢ' => 'S', 'Ⓣ' => 'T', 'Ⓤ' => 'U', 'Ⓥ' => 'V', 'Ⓦ' => 'W', 'Ⓧ' => 'X', 'Ⓨ' => 'Y', 'Ⓩ' => 'Z', 'ⓐ' => 'a', 'ⓑ' => 'b', 'ⓒ' => 'c', 'ⓓ' => 'd', 'ⓔ' => 'e', 'ⓕ' => 'f', 'ⓖ' => 'g', 'ⓗ' => 'h', 'ⓘ' => 'i', 'ⓙ' => 'j', 'ⓚ' => 'k', 'ⓛ' => 'l', 'ⓜ' => 'm', 'ⓝ' => 'n', 'ⓞ' => 'o', 'ⓟ' => 'p', 'ⓠ' => 'q', 'ⓡ' => 'r', 'ⓢ' => 's', 'ⓣ' => 't', 'ⓤ' => 'u', 'ⓥ' => 'v', 'ⓦ' => 'w', 'ⓧ' => 'x', 'ⓨ' => 'y', 'ⓩ' => 'z', '⓪' => '0', '⨌' => '∫∫∫∫', '⩴' => '::=', '⩵' => '==', '⩶' => '===', 'ⱼ' => 'j', 'ⱽ' => 'V', 'ⵯ' => 'ⵡ', '⺟' => '母', '⻳' => '龟', '⼀' => '一', '⼁' => '丨', '⼂' => '丶', '⼃' => '丿', '⼄' => '乙', '⼅' => '亅', '⼆' => '二', '⼇' => '亠', '⼈' => '人', '⼉' => '儿', '⼊' => '入', '⼋' => '八', '⼌' => '冂', '⼍' => '冖', '⼎' => '冫', '⼏' => '几', '⼐' => '凵', '⼑' => '刀', '⼒' => '力', '⼓' => '勹', '⼔' => '匕', '⼕' => '匚', '⼖' => '匸', '⼗' => '十', '⼘' => '卜', '⼙' => '卩', '⼚' => '厂', '⼛' => '厶', '⼜' => '又', '⼝' => '口', '⼞' => '囗', '⼟' => '土', '⼠' => '士', '⼡' => '夂', '⼢' => '夊', '⼣' => '夕', '⼤' => '大', '⼥' => '女', '⼦' => '子', '⼧' => '宀', '⼨' => '寸', '⼩' => '小', '⼪' => '尢', '⼫' => '尸', '⼬' => '屮', '⼭' => '山', '⼮' => '巛', '⼯' => '工', '⼰' => '己', '⼱' => '巾', '⼲' => '干', '⼳' => '幺', '⼴' => '广', '⼵' => '廴', '⼶' => '廾', '⼷' => '弋', '⼸' => '弓', '⼹' => '彐', '⼺' => '彡', '⼻' => '彳', '⼼' => '心', '⼽' => '戈', '⼾' => '戶', '⼿' => '手', '⽀' => '支', '⽁' => '攴', '⽂' => '文', '⽃' => '斗', '⽄' => '斤', '⽅' => '方', '⽆' => '无', '⽇' => '日', '⽈' => '曰', '⽉' => '月', '⽊' => '木', '⽋' => '欠', '⽌' => '止', '⽍' => '歹', '⽎' => '殳', '⽏' => '毋', '⽐' => '比', '⽑' => '毛', '⽒' => '氏', '⽓' => '气', '⽔' => '水', '⽕' => '火', '⽖' => '爪', '⽗' => '父', '⽘' => '爻', '⽙' => '爿', '⽚' => '片', '⽛' => '牙', '⽜' => '牛', '⽝' => '犬', '⽞' => '玄', '⽟' => '玉', '⽠' => '瓜', '⽡' => '瓦', '⽢' => '甘', '⽣' => '生', '⽤' => '用', '⽥' => '田', '⽦' => '疋', '⽧' => '疒', '⽨' => '癶', '⽩' => '白', '⽪' => '皮', '⽫' => '皿', '⽬' => '目', '⽭' => '矛', '⽮' => '矢', '⽯' => '石', '⽰' => '示', '⽱' => '禸', '⽲' => '禾', '⽳' => '穴', '⽴' => '立', '⽵' => '竹', '⽶' => '米', '⽷' => '糸', '⽸' => '缶', '⽹' => '网', '⽺' => '羊', '⽻' => '羽', '⽼' => '老', '⽽' => '而', '⽾' => '耒', '⽿' => '耳', '⾀' => '聿', '⾁' => '肉', '⾂' => '臣', '⾃' => '自', '⾄' => '至', '⾅' => '臼', '⾆' => '舌', '⾇' => '舛', '⾈' => '舟', '⾉' => '艮', '⾊' => '色', '⾋' => '艸', '⾌' => '虍', '⾍' => '虫', '⾎' => '血', '⾏' => '行', '⾐' => '衣', '⾑' => '襾', '⾒' => '見', '⾓' => '角', '⾔' => '言', '⾕' => '谷', '⾖' => '豆', '⾗' => '豕', '⾘' => '豸', '⾙' => '貝', '⾚' => '赤', '⾛' => '走', '⾜' => '足', '⾝' => '身', '⾞' => '車', '⾟' => '辛', '⾠' => '辰', '⾡' => '辵', '⾢' => '邑', '⾣' => '酉', '⾤' => '釆', '⾥' => '里', '⾦' => '金', '⾧' => '長', '⾨' => '門', '⾩' => '阜', '⾪' => '隶', '⾫' => '隹', '⾬' => '雨', '⾭' => '靑', '⾮' => '非', '⾯' => '面', '⾰' => '革', '⾱' => '韋', '⾲' => '韭', '⾳' => '音', '⾴' => '頁', '⾵' => '風', '⾶' => '飛', '⾷' => '食', '⾸' => '首', '⾹' => '香', '⾺' => '馬', '⾻' => '骨', '⾼' => '高', '⾽' => '髟', '⾾' => '鬥', '⾿' => '鬯', '⿀' => '鬲', '⿁' => '鬼', '⿂' => '魚', '⿃' => '鳥', '⿄' => '鹵', '⿅' => '鹿', '⿆' => '麥', '⿇' => '麻', '⿈' => '黃', '⿉' => '黍', '⿊' => '黑', '⿋' => '黹', '⿌' => '黽', '⿍' => '鼎', '⿎' => '鼓', '⿏' => '鼠', '⿐' => '鼻', '⿑' => '齊', '⿒' => '齒', '⿓' => '龍', '⿔' => '龜', '⿕' => '龠', ' ' => ' ', '〶' => '〒', '〸' => '十', '〹' => '卄', '〺' => '卅', '゛' => ' ゙', '゜' => ' ゚', 'ゟ' => 'より', 'ヿ' => 'コト', 'ㄱ' => 'ᄀ', 'ㄲ' => 'ᄁ', 'ㄳ' => 'ᆪ', 'ㄴ' => 'ᄂ', 'ㄵ' => 'ᆬ', 'ㄶ' => 'ᆭ', 'ㄷ' => 'ᄃ', 'ㄸ' => 'ᄄ', 'ㄹ' => 'ᄅ', 'ㄺ' => 'ᆰ', 'ㄻ' => 'ᆱ', 'ㄼ' => 'ᆲ', 'ㄽ' => 'ᆳ', 'ㄾ' => 'ᆴ', 'ㄿ' => 'ᆵ', 'ㅀ' => 'ᄚ', 'ㅁ' => 'ᄆ', 'ㅂ' => 'ᄇ', 'ㅃ' => 'ᄈ', 'ㅄ' => 'ᄡ', 'ㅅ' => 'ᄉ', 'ㅆ' => 'ᄊ', 'ㅇ' => 'ᄋ', 'ㅈ' => 'ᄌ', 'ㅉ' => 'ᄍ', 'ㅊ' => 'ᄎ', 'ㅋ' => 'ᄏ', 'ㅌ' => 'ᄐ', 'ㅍ' => 'ᄑ', 'ㅎ' => 'ᄒ', 'ㅏ' => 'ᅡ', 'ㅐ' => 'ᅢ', 'ㅑ' => 'ᅣ', 'ㅒ' => 'ᅤ', 'ㅓ' => 'ᅥ', 'ㅔ' => 'ᅦ', 'ㅕ' => 'ᅧ', 'ㅖ' => 'ᅨ', 'ㅗ' => 'ᅩ', 'ㅘ' => 'ᅪ', 'ㅙ' => 'ᅫ', 'ㅚ' => 'ᅬ', 'ㅛ' => 'ᅭ', 'ㅜ' => 'ᅮ', 'ㅝ' => 'ᅯ', 'ㅞ' => 'ᅰ', 'ㅟ' => 'ᅱ', 'ㅠ' => 'ᅲ', 'ㅡ' => 'ᅳ', 'ㅢ' => 'ᅴ', 'ㅣ' => 'ᅵ', 'ㅤ' => 'ᅠ', 'ㅥ' => 'ᄔ', 'ㅦ' => 'ᄕ', 'ㅧ' => 'ᇇ', 'ㅨ' => 'ᇈ', 'ㅩ' => 'ᇌ', 'ㅪ' => 'ᇎ', 'ㅫ' => 'ᇓ', 'ㅬ' => 'ᇗ', 'ㅭ' => 'ᇙ', 'ㅮ' => 'ᄜ', 'ㅯ' => 'ᇝ', 'ㅰ' => 'ᇟ', 'ㅱ' => 'ᄝ', 'ㅲ' => 'ᄞ', 'ㅳ' => 'ᄠ', 'ㅴ' => 'ᄢ', 'ㅵ' => 'ᄣ', 'ㅶ' => 'ᄧ', 'ㅷ' => 'ᄩ', 'ㅸ' => 'ᄫ', 'ㅹ' => 'ᄬ', 'ㅺ' => 'ᄭ', 'ㅻ' => 'ᄮ', 'ㅼ' => 'ᄯ', 'ㅽ' => 'ᄲ', 'ㅾ' => 'ᄶ', 'ㅿ' => 'ᅀ', 'ㆀ' => 'ᅇ', 'ㆁ' => 'ᅌ', 'ㆂ' => 'ᇱ', 'ㆃ' => 'ᇲ', 'ㆄ' => 'ᅗ', 'ㆅ' => 'ᅘ', 'ㆆ' => 'ᅙ', 'ㆇ' => 'ᆄ', 'ㆈ' => 'ᆅ', 'ㆉ' => 'ᆈ', 'ㆊ' => 'ᆑ', 'ㆋ' => 'ᆒ', 'ㆌ' => 'ᆔ', 'ㆍ' => 'ᆞ', 'ㆎ' => 'ᆡ', '㆒' => '一', '㆓' => '二', '㆔' => '三', '㆕' => '四', '㆖' => '上', '㆗' => '中', '㆘' => '下', '㆙' => '甲', '㆚' => '乙', '㆛' => '丙', '㆜' => '丁', '㆝' => '天', '㆞' => '地', '㆟' => '人', '㈀' => '(ᄀ)', '㈁' => '(ᄂ)', '㈂' => '(ᄃ)', '㈃' => '(ᄅ)', '㈄' => '(ᄆ)', '㈅' => '(ᄇ)', '㈆' => '(ᄉ)', '㈇' => '(ᄋ)', '㈈' => '(ᄌ)', '㈉' => '(ᄎ)', '㈊' => '(ᄏ)', '㈋' => '(ᄐ)', '㈌' => '(ᄑ)', '㈍' => '(ᄒ)', '㈎' => '(가)', '㈏' => '(나)', '㈐' => '(다)', '㈑' => '(라)', '㈒' => '(마)', '㈓' => '(바)', '㈔' => '(사)', '㈕' => '(아)', '㈖' => '(자)', '㈗' => '(차)', '㈘' => '(카)', '㈙' => '(타)', '㈚' => '(파)', '㈛' => '(하)', '㈜' => '(주)', '㈝' => '(오전)', '㈞' => '(오후)', '㈠' => '(一)', '㈡' => '(二)', '㈢' => '(三)', '㈣' => '(四)', '㈤' => '(五)', '㈥' => '(六)', '㈦' => '(七)', '㈧' => '(八)', '㈨' => '(九)', '㈩' => '(十)', '㈪' => '(月)', '㈫' => '(火)', '㈬' => '(水)', '㈭' => '(木)', '㈮' => '(金)', '㈯' => '(土)', '㈰' => '(日)', '㈱' => '(株)', '㈲' => '(有)', '㈳' => '(社)', '㈴' => '(名)', '㈵' => '(特)', '㈶' => '(財)', '㈷' => '(祝)', '㈸' => '(労)', '㈹' => '(代)', '㈺' => '(呼)', '㈻' => '(学)', '㈼' => '(監)', '㈽' => '(企)', '㈾' => '(資)', '㈿' => '(協)', '㉀' => '(祭)', '㉁' => '(休)', '㉂' => '(自)', '㉃' => '(至)', '㉄' => '問', '㉅' => '幼', '㉆' => '文', '㉇' => '箏', '㉐' => 'PTE', '㉑' => '21', '㉒' => '22', '㉓' => '23', '㉔' => '24', '㉕' => '25', '㉖' => '26', '㉗' => '27', '㉘' => '28', '㉙' => '29', '㉚' => '30', '㉛' => '31', '㉜' => '32', '㉝' => '33', '㉞' => '34', '㉟' => '35', '㉠' => 'ᄀ', '㉡' => 'ᄂ', '㉢' => 'ᄃ', '㉣' => 'ᄅ', '㉤' => 'ᄆ', '㉥' => 'ᄇ', '㉦' => 'ᄉ', '㉧' => 'ᄋ', '㉨' => 'ᄌ', '㉩' => 'ᄎ', '㉪' => 'ᄏ', '㉫' => 'ᄐ', '㉬' => 'ᄑ', '㉭' => 'ᄒ', '㉮' => '가', '㉯' => '나', '㉰' => '다', '㉱' => '라', '㉲' => '마', '㉳' => '바', '㉴' => '사', '㉵' => '아', '㉶' => '자', '㉷' => '차', '㉸' => '카', '㉹' => '타', '㉺' => '파', '㉻' => '하', '㉼' => '참고', '㉽' => '주의', '㉾' => '우', '㊀' => '一', '㊁' => '二', '㊂' => '三', '㊃' => '四', '㊄' => '五', '㊅' => '六', '㊆' => '七', '㊇' => '八', '㊈' => '九', '㊉' => '十', '㊊' => '月', '㊋' => '火', '㊌' => '水', '㊍' => '木', '㊎' => '金', '㊏' => '土', '㊐' => '日', '㊑' => '株', '㊒' => '有', '㊓' => '社', '㊔' => '名', '㊕' => '特', '㊖' => '財', '㊗' => '祝', '㊘' => '労', '㊙' => '秘', '㊚' => '男', '㊛' => '女', '㊜' => '適', '㊝' => '優', '㊞' => '印', '㊟' => '注', '㊠' => '項', '㊡' => '休', '㊢' => '写', '㊣' => '正', '㊤' => '上', '㊥' => '中', '㊦' => '下', '㊧' => '左', '㊨' => '右', '㊩' => '医', '㊪' => '宗', '㊫' => '学', '㊬' => '監', '㊭' => '企', '㊮' => '資', '㊯' => '協', '㊰' => '夜', '㊱' => '36', '㊲' => '37', '㊳' => '38', '㊴' => '39', '㊵' => '40', '㊶' => '41', '㊷' => '42', '㊸' => '43', '㊹' => '44', '㊺' => '45', '㊻' => '46', '㊼' => '47', '㊽' => '48', '㊾' => '49', '㊿' => '50', '㋀' => '1月', '㋁' => '2月', '㋂' => '3月', '㋃' => '4月', '㋄' => '5月', '㋅' => '6月', '㋆' => '7月', '㋇' => '8月', '㋈' => '9月', '㋉' => '10月', '㋊' => '11月', '㋋' => '12月', '㋌' => 'Hg', '㋍' => 'erg', '㋎' => 'eV', '㋏' => 'LTD', '㋐' => 'ア', '㋑' => 'イ', '㋒' => 'ウ', '㋓' => 'エ', '㋔' => 'オ', '㋕' => 'カ', '㋖' => 'キ', '㋗' => 'ク', '㋘' => 'ケ', '㋙' => 'コ', '㋚' => 'サ', '㋛' => 'シ', '㋜' => 'ス', '㋝' => 'セ', '㋞' => 'ソ', '㋟' => 'タ', '㋠' => 'チ', '㋡' => 'ツ', '㋢' => 'テ', '㋣' => 'ト', '㋤' => 'ナ', '㋥' => 'ニ', '㋦' => 'ヌ', '㋧' => 'ネ', '㋨' => 'ノ', '㋩' => 'ハ', '㋪' => 'ヒ', '㋫' => 'フ', '㋬' => 'ヘ', '㋭' => 'ホ', '㋮' => 'マ', '㋯' => 'ミ', '㋰' => 'ム', '㋱' => 'メ', '㋲' => 'モ', '㋳' => 'ヤ', '㋴' => 'ユ', '㋵' => 'ヨ', '㋶' => 'ラ', '㋷' => 'リ', '㋸' => 'ル', '㋹' => 'レ', '㋺' => 'ロ', '㋻' => 'ワ', '㋼' => 'ヰ', '㋽' => 'ヱ', '㋾' => 'ヲ', '㋿' => '令和', '㌀' => 'アパート', '㌁' => 'アルファ', '㌂' => 'アンペア', '㌃' => 'アール', '㌄' => 'イニング', '㌅' => 'インチ', '㌆' => 'ウォン', '㌇' => 'エスクード', '㌈' => 'エーカー', '㌉' => 'オンス', '㌊' => 'オーム', '㌋' => 'カイリ', '㌌' => 'カラット', '㌍' => 'カロリー', '㌎' => 'ガロン', '㌏' => 'ガンマ', '㌐' => 'ギガ', '㌑' => 'ギニー', '㌒' => 'キュリー', '㌓' => 'ギルダー', '㌔' => 'キロ', '㌕' => 'キログラム', '㌖' => 'キロメートル', '㌗' => 'キロワット', '㌘' => 'グラム', '㌙' => 'グラムトン', '㌚' => 'クルゼイロ', '㌛' => 'クローネ', '㌜' => 'ケース', '㌝' => 'コルナ', '㌞' => 'コーポ', '㌟' => 'サイクル', '㌠' => 'サンチーム', '㌡' => 'シリング', '㌢' => 'センチ', '㌣' => 'セント', '㌤' => 'ダース', '㌥' => 'デシ', '㌦' => 'ドル', '㌧' => 'トン', '㌨' => 'ナノ', '㌩' => 'ノット', '㌪' => 'ハイツ', '㌫' => 'パーセント', '㌬' => 'パーツ', '㌭' => 'バーレル', '㌮' => 'ピアストル', '㌯' => 'ピクル', '㌰' => 'ピコ', '㌱' => 'ビル', '㌲' => 'ファラッド', '㌳' => 'フィート', '㌴' => 'ブッシェル', '㌵' => 'フラン', '㌶' => 'ヘクタール', '㌷' => 'ペソ', '㌸' => 'ペニヒ', '㌹' => 'ヘルツ', '㌺' => 'ペンス', '㌻' => 'ページ', '㌼' => 'ベータ', '㌽' => 'ポイント', '㌾' => 'ボルト', '㌿' => 'ホン', '㍀' => 'ポンド', '㍁' => 'ホール', '㍂' => 'ホーン', '㍃' => 'マイクロ', '㍄' => 'マイル', '㍅' => 'マッハ', '㍆' => 'マルク', '㍇' => 'マンション', '㍈' => 'ミクロン', '㍉' => 'ミリ', '㍊' => 'ミリバール', '㍋' => 'メガ', '㍌' => 'メガトン', '㍍' => 'メートル', '㍎' => 'ヤード', '㍏' => 'ヤール', '㍐' => 'ユアン', '㍑' => 'リットル', '㍒' => 'リラ', '㍓' => 'ルピー', '㍔' => 'ルーブル', '㍕' => 'レム', '㍖' => 'レントゲン', '㍗' => 'ワット', '㍘' => '0点', '㍙' => '1点', '㍚' => '2点', '㍛' => '3点', '㍜' => '4点', '㍝' => '5点', '㍞' => '6点', '㍟' => '7点', '㍠' => '8点', '㍡' => '9点', '㍢' => '10点', '㍣' => '11点', '㍤' => '12点', '㍥' => '13点', '㍦' => '14点', '㍧' => '15点', '㍨' => '16点', '㍩' => '17点', '㍪' => '18点', '㍫' => '19点', '㍬' => '20点', '㍭' => '21点', '㍮' => '22点', '㍯' => '23点', '㍰' => '24点', '㍱' => 'hPa', '㍲' => 'da', '㍳' => 'AU', '㍴' => 'bar', '㍵' => 'oV', '㍶' => 'pc', '㍷' => 'dm', '㍸' => 'dm2', '㍹' => 'dm3', '㍺' => 'IU', '㍻' => '平成', '㍼' => '昭和', '㍽' => '大正', '㍾' => '明治', '㍿' => '株式会社', '㎀' => 'pA', '㎁' => 'nA', '㎂' => 'μA', '㎃' => 'mA', '㎄' => 'kA', '㎅' => 'KB', '㎆' => 'MB', '㎇' => 'GB', '㎈' => 'cal', '㎉' => 'kcal', '㎊' => 'pF', '㎋' => 'nF', '㎌' => 'μF', '㎍' => 'μg', '㎎' => 'mg', '㎏' => 'kg', '㎐' => 'Hz', '㎑' => 'kHz', '㎒' => 'MHz', '㎓' => 'GHz', '㎔' => 'THz', '㎕' => 'μl', '㎖' => 'ml', '㎗' => 'dl', '㎘' => 'kl', '㎙' => 'fm', '㎚' => 'nm', '㎛' => 'μm', '㎜' => 'mm', '㎝' => 'cm', '㎞' => 'km', '㎟' => 'mm2', '㎠' => 'cm2', '㎡' => 'm2', '㎢' => 'km2', '㎣' => 'mm3', '㎤' => 'cm3', '㎥' => 'm3', '㎦' => 'km3', '㎧' => 'm∕s', '㎨' => 'm∕s2', '㎩' => 'Pa', '㎪' => 'kPa', '㎫' => 'MPa', '㎬' => 'GPa', '㎭' => 'rad', '㎮' => 'rad∕s', '㎯' => 'rad∕s2', '㎰' => 'ps', '㎱' => 'ns', '㎲' => 'μs', '㎳' => 'ms', '㎴' => 'pV', '㎵' => 'nV', '㎶' => 'μV', '㎷' => 'mV', '㎸' => 'kV', '㎹' => 'MV', '㎺' => 'pW', '㎻' => 'nW', '㎼' => 'μW', '㎽' => 'mW', '㎾' => 'kW', '㎿' => 'MW', '㏀' => 'kΩ', '㏁' => 'MΩ', '㏂' => 'a.m.', '㏃' => 'Bq', '㏄' => 'cc', '㏅' => 'cd', '㏆' => 'C∕kg', '㏇' => 'Co.', '㏈' => 'dB', '㏉' => 'Gy', '㏊' => 'ha', '㏋' => 'HP', '㏌' => 'in', '㏍' => 'KK', '㏎' => 'KM', '㏏' => 'kt', '㏐' => 'lm', '㏑' => 'ln', '㏒' => 'log', '㏓' => 'lx', '㏔' => 'mb', '㏕' => 'mil', '㏖' => 'mol', '㏗' => 'PH', '㏘' => 'p.m.', '㏙' => 'PPM', '㏚' => 'PR', '㏛' => 'sr', '㏜' => 'Sv', '㏝' => 'Wb', '㏞' => 'V∕m', '㏟' => 'A∕m', '㏠' => '1日', '㏡' => '2日', '㏢' => '3日', '㏣' => '4日', '㏤' => '5日', '㏥' => '6日', '㏦' => '7日', '㏧' => '8日', '㏨' => '9日', '㏩' => '10日', '㏪' => '11日', '㏫' => '12日', '㏬' => '13日', '㏭' => '14日', '㏮' => '15日', '㏯' => '16日', '㏰' => '17日', '㏱' => '18日', '㏲' => '19日', '㏳' => '20日', '㏴' => '21日', '㏵' => '22日', '㏶' => '23日', '㏷' => '24日', '㏸' => '25日', '㏹' => '26日', '㏺' => '27日', '㏻' => '28日', '㏼' => '29日', '㏽' => '30日', '㏾' => '31日', '㏿' => 'gal', 'ꚜ' => 'ъ', 'ꚝ' => 'ь', 'ꝰ' => 'ꝯ', 'ꟸ' => 'Ħ', 'ꟹ' => 'œ', 'ꭜ' => 'ꜧ', 'ꭝ' => 'ꬷ', 'ꭞ' => 'ɫ', 'ꭟ' => 'ꭒ', 'ꭩ' => 'ʍ', 'ff' => 'ff', 'fi' => 'fi', 'fl' => 'fl', 'ffi' => 'ffi', 'ffl' => 'ffl', 'ſt' => 'st', 'st' => 'st', 'ﬓ' => 'մն', 'ﬔ' => 'մե', 'ﬕ' => 'մի', 'ﬖ' => 'վն', 'ﬗ' => 'մխ', 'ﬠ' => 'ע', 'ﬡ' => 'א', 'ﬢ' => 'ד', 'ﬣ' => 'ה', 'ﬤ' => 'כ', 'ﬥ' => 'ל', 'ﬦ' => 'ם', 'ﬧ' => 'ר', 'ﬨ' => 'ת', '﬩' => '+', 'ﭏ' => 'אל', 'ﭐ' => 'ٱ', 'ﭑ' => 'ٱ', 'ﭒ' => 'ٻ', 'ﭓ' => 'ٻ', 'ﭔ' => 'ٻ', 'ﭕ' => 'ٻ', 'ﭖ' => 'پ', 'ﭗ' => 'پ', 'ﭘ' => 'پ', 'ﭙ' => 'پ', 'ﭚ' => 'ڀ', 'ﭛ' => 'ڀ', 'ﭜ' => 'ڀ', 'ﭝ' => 'ڀ', 'ﭞ' => 'ٺ', 'ﭟ' => 'ٺ', 'ﭠ' => 'ٺ', 'ﭡ' => 'ٺ', 'ﭢ' => 'ٿ', 'ﭣ' => 'ٿ', 'ﭤ' => 'ٿ', 'ﭥ' => 'ٿ', 'ﭦ' => 'ٹ', 'ﭧ' => 'ٹ', 'ﭨ' => 'ٹ', 'ﭩ' => 'ٹ', 'ﭪ' => 'ڤ', 'ﭫ' => 'ڤ', 'ﭬ' => 'ڤ', 'ﭭ' => 'ڤ', 'ﭮ' => 'ڦ', 'ﭯ' => 'ڦ', 'ﭰ' => 'ڦ', 'ﭱ' => 'ڦ', 'ﭲ' => 'ڄ', 'ﭳ' => 'ڄ', 'ﭴ' => 'ڄ', 'ﭵ' => 'ڄ', 'ﭶ' => 'ڃ', 'ﭷ' => 'ڃ', 'ﭸ' => 'ڃ', 'ﭹ' => 'ڃ', 'ﭺ' => 'چ', 'ﭻ' => 'چ', 'ﭼ' => 'چ', 'ﭽ' => 'چ', 'ﭾ' => 'ڇ', 'ﭿ' => 'ڇ', 'ﮀ' => 'ڇ', 'ﮁ' => 'ڇ', 'ﮂ' => 'ڍ', 'ﮃ' => 'ڍ', 'ﮄ' => 'ڌ', 'ﮅ' => 'ڌ', 'ﮆ' => 'ڎ', 'ﮇ' => 'ڎ', 'ﮈ' => 'ڈ', 'ﮉ' => 'ڈ', 'ﮊ' => 'ژ', 'ﮋ' => 'ژ', 'ﮌ' => 'ڑ', 'ﮍ' => 'ڑ', 'ﮎ' => 'ک', 'ﮏ' => 'ک', 'ﮐ' => 'ک', 'ﮑ' => 'ک', 'ﮒ' => 'گ', 'ﮓ' => 'گ', 'ﮔ' => 'گ', 'ﮕ' => 'گ', 'ﮖ' => 'ڳ', 'ﮗ' => 'ڳ', 'ﮘ' => 'ڳ', 'ﮙ' => 'ڳ', 'ﮚ' => 'ڱ', 'ﮛ' => 'ڱ', 'ﮜ' => 'ڱ', 'ﮝ' => 'ڱ', 'ﮞ' => 'ں', 'ﮟ' => 'ں', 'ﮠ' => 'ڻ', 'ﮡ' => 'ڻ', 'ﮢ' => 'ڻ', 'ﮣ' => 'ڻ', 'ﮤ' => 'ۀ', 'ﮥ' => 'ۀ', 'ﮦ' => 'ہ', 'ﮧ' => 'ہ', 'ﮨ' => 'ہ', 'ﮩ' => 'ہ', 'ﮪ' => 'ھ', 'ﮫ' => 'ھ', 'ﮬ' => 'ھ', 'ﮭ' => 'ھ', 'ﮮ' => 'ے', 'ﮯ' => 'ے', 'ﮰ' => 'ۓ', 'ﮱ' => 'ۓ', 'ﯓ' => 'ڭ', 'ﯔ' => 'ڭ', 'ﯕ' => 'ڭ', 'ﯖ' => 'ڭ', 'ﯗ' => 'ۇ', 'ﯘ' => 'ۇ', 'ﯙ' => 'ۆ', 'ﯚ' => 'ۆ', 'ﯛ' => 'ۈ', 'ﯜ' => 'ۈ', 'ﯝ' => 'ۇٴ', 'ﯞ' => 'ۋ', 'ﯟ' => 'ۋ', 'ﯠ' => 'ۅ', 'ﯡ' => 'ۅ', 'ﯢ' => 'ۉ', 'ﯣ' => 'ۉ', 'ﯤ' => 'ې', 'ﯥ' => 'ې', 'ﯦ' => 'ې', 'ﯧ' => 'ې', 'ﯨ' => 'ى', 'ﯩ' => 'ى', 'ﯪ' => 'ئا', 'ﯫ' => 'ئا', 'ﯬ' => 'ئە', 'ﯭ' => 'ئە', 'ﯮ' => 'ئو', 'ﯯ' => 'ئو', 'ﯰ' => 'ئۇ', 'ﯱ' => 'ئۇ', 'ﯲ' => 'ئۆ', 'ﯳ' => 'ئۆ', 'ﯴ' => 'ئۈ', 'ﯵ' => 'ئۈ', 'ﯶ' => 'ئې', 'ﯷ' => 'ئې', 'ﯸ' => 'ئې', 'ﯹ' => 'ئى', 'ﯺ' => 'ئى', 'ﯻ' => 'ئى', 'ﯼ' => 'ی', 'ﯽ' => 'ی', 'ﯾ' => 'ی', 'ﯿ' => 'ی', 'ﰀ' => 'ئج', 'ﰁ' => 'ئح', 'ﰂ' => 'ئم', 'ﰃ' => 'ئى', 'ﰄ' => 'ئي', 'ﰅ' => 'بج', 'ﰆ' => 'بح', 'ﰇ' => 'بخ', 'ﰈ' => 'بم', 'ﰉ' => 'بى', 'ﰊ' => 'بي', 'ﰋ' => 'تج', 'ﰌ' => 'تح', 'ﰍ' => 'تخ', 'ﰎ' => 'تم', 'ﰏ' => 'تى', 'ﰐ' => 'تي', 'ﰑ' => 'ثج', 'ﰒ' => 'ثم', 'ﰓ' => 'ثى', 'ﰔ' => 'ثي', 'ﰕ' => 'جح', 'ﰖ' => 'جم', 'ﰗ' => 'حج', 'ﰘ' => 'حم', 'ﰙ' => 'خج', 'ﰚ' => 'خح', 'ﰛ' => 'خم', 'ﰜ' => 'سج', 'ﰝ' => 'سح', 'ﰞ' => 'سخ', 'ﰟ' => 'سم', 'ﰠ' => 'صح', 'ﰡ' => 'صم', 'ﰢ' => 'ضج', 'ﰣ' => 'ضح', 'ﰤ' => 'ضخ', 'ﰥ' => 'ضم', 'ﰦ' => 'طح', 'ﰧ' => 'طم', 'ﰨ' => 'ظم', 'ﰩ' => 'عج', 'ﰪ' => 'عم', 'ﰫ' => 'غج', 'ﰬ' => 'غم', 'ﰭ' => 'فج', 'ﰮ' => 'فح', 'ﰯ' => 'فخ', 'ﰰ' => 'فم', 'ﰱ' => 'فى', 'ﰲ' => 'في', 'ﰳ' => 'قح', 'ﰴ' => 'قم', 'ﰵ' => 'قى', 'ﰶ' => 'قي', 'ﰷ' => 'كا', 'ﰸ' => 'كج', 'ﰹ' => 'كح', 'ﰺ' => 'كخ', 'ﰻ' => 'كل', 'ﰼ' => 'كم', 'ﰽ' => 'كى', 'ﰾ' => 'كي', 'ﰿ' => 'لج', 'ﱀ' => 'لح', 'ﱁ' => 'لخ', 'ﱂ' => 'لم', 'ﱃ' => 'لى', 'ﱄ' => 'لي', 'ﱅ' => 'مج', 'ﱆ' => 'مح', 'ﱇ' => 'مخ', 'ﱈ' => 'مم', 'ﱉ' => 'مى', 'ﱊ' => 'مي', 'ﱋ' => 'نج', 'ﱌ' => 'نح', 'ﱍ' => 'نخ', 'ﱎ' => 'نم', 'ﱏ' => 'نى', 'ﱐ' => 'ني', 'ﱑ' => 'هج', 'ﱒ' => 'هم', 'ﱓ' => 'هى', 'ﱔ' => 'هي', 'ﱕ' => 'يج', 'ﱖ' => 'يح', 'ﱗ' => 'يخ', 'ﱘ' => 'يم', 'ﱙ' => 'يى', 'ﱚ' => 'يي', 'ﱛ' => 'ذٰ', 'ﱜ' => 'رٰ', 'ﱝ' => 'ىٰ', 'ﱞ' => ' ٌّ', 'ﱟ' => ' ٍّ', 'ﱠ' => ' َّ', 'ﱡ' => ' ُّ', 'ﱢ' => ' ِّ', 'ﱣ' => ' ّٰ', 'ﱤ' => 'ئر', 'ﱥ' => 'ئز', 'ﱦ' => 'ئم', 'ﱧ' => 'ئن', 'ﱨ' => 'ئى', 'ﱩ' => 'ئي', 'ﱪ' => 'بر', 'ﱫ' => 'بز', 'ﱬ' => 'بم', 'ﱭ' => 'بن', 'ﱮ' => 'بى', 'ﱯ' => 'بي', 'ﱰ' => 'تر', 'ﱱ' => 'تز', 'ﱲ' => 'تم', 'ﱳ' => 'تن', 'ﱴ' => 'تى', 'ﱵ' => 'تي', 'ﱶ' => 'ثر', 'ﱷ' => 'ثز', 'ﱸ' => 'ثم', 'ﱹ' => 'ثن', 'ﱺ' => 'ثى', 'ﱻ' => 'ثي', 'ﱼ' => 'فى', 'ﱽ' => 'في', 'ﱾ' => 'قى', 'ﱿ' => 'قي', 'ﲀ' => 'كا', 'ﲁ' => 'كل', 'ﲂ' => 'كم', 'ﲃ' => 'كى', 'ﲄ' => 'كي', 'ﲅ' => 'لم', 'ﲆ' => 'لى', 'ﲇ' => 'لي', 'ﲈ' => 'ما', 'ﲉ' => 'مم', 'ﲊ' => 'نر', 'ﲋ' => 'نز', 'ﲌ' => 'نم', 'ﲍ' => 'نن', 'ﲎ' => 'نى', 'ﲏ' => 'ني', 'ﲐ' => 'ىٰ', 'ﲑ' => 'ير', 'ﲒ' => 'يز', 'ﲓ' => 'يم', 'ﲔ' => 'ين', 'ﲕ' => 'يى', 'ﲖ' => 'يي', 'ﲗ' => 'ئج', 'ﲘ' => 'ئح', 'ﲙ' => 'ئخ', 'ﲚ' => 'ئم', 'ﲛ' => 'ئه', 'ﲜ' => 'بج', 'ﲝ' => 'بح', 'ﲞ' => 'بخ', 'ﲟ' => 'بم', 'ﲠ' => 'به', 'ﲡ' => 'تج', 'ﲢ' => 'تح', 'ﲣ' => 'تخ', 'ﲤ' => 'تم', 'ﲥ' => 'ته', 'ﲦ' => 'ثم', 'ﲧ' => 'جح', 'ﲨ' => 'جم', 'ﲩ' => 'حج', 'ﲪ' => 'حم', 'ﲫ' => 'خج', 'ﲬ' => 'خم', 'ﲭ' => 'سج', 'ﲮ' => 'سح', 'ﲯ' => 'سخ', 'ﲰ' => 'سم', 'ﲱ' => 'صح', 'ﲲ' => 'صخ', 'ﲳ' => 'صم', 'ﲴ' => 'ضج', 'ﲵ' => 'ضح', 'ﲶ' => 'ضخ', 'ﲷ' => 'ضم', 'ﲸ' => 'طح', 'ﲹ' => 'ظم', 'ﲺ' => 'عج', 'ﲻ' => 'عم', 'ﲼ' => 'غج', 'ﲽ' => 'غم', 'ﲾ' => 'فج', 'ﲿ' => 'فح', 'ﳀ' => 'فخ', 'ﳁ' => 'فم', 'ﳂ' => 'قح', 'ﳃ' => 'قم', 'ﳄ' => 'كج', 'ﳅ' => 'كح', 'ﳆ' => 'كخ', 'ﳇ' => 'كل', 'ﳈ' => 'كم', 'ﳉ' => 'لج', 'ﳊ' => 'لح', 'ﳋ' => 'لخ', 'ﳌ' => 'لم', 'ﳍ' => 'له', 'ﳎ' => 'مج', 'ﳏ' => 'مح', 'ﳐ' => 'مخ', 'ﳑ' => 'مم', 'ﳒ' => 'نج', 'ﳓ' => 'نح', 'ﳔ' => 'نخ', 'ﳕ' => 'نم', 'ﳖ' => 'نه', 'ﳗ' => 'هج', 'ﳘ' => 'هم', 'ﳙ' => 'هٰ', 'ﳚ' => 'يج', 'ﳛ' => 'يح', 'ﳜ' => 'يخ', 'ﳝ' => 'يم', 'ﳞ' => 'يه', 'ﳟ' => 'ئم', 'ﳠ' => 'ئه', 'ﳡ' => 'بم', 'ﳢ' => 'به', 'ﳣ' => 'تم', 'ﳤ' => 'ته', 'ﳥ' => 'ثم', 'ﳦ' => 'ثه', 'ﳧ' => 'سم', 'ﳨ' => 'سه', 'ﳩ' => 'شم', 'ﳪ' => 'شه', 'ﳫ' => 'كل', 'ﳬ' => 'كم', 'ﳭ' => 'لم', 'ﳮ' => 'نم', 'ﳯ' => 'نه', 'ﳰ' => 'يم', 'ﳱ' => 'يه', 'ﳲ' => 'ـَّ', 'ﳳ' => 'ـُّ', 'ﳴ' => 'ـِّ', 'ﳵ' => 'طى', 'ﳶ' => 'طي', 'ﳷ' => 'عى', 'ﳸ' => 'عي', 'ﳹ' => 'غى', 'ﳺ' => 'غي', 'ﳻ' => 'سى', 'ﳼ' => 'سي', 'ﳽ' => 'شى', 'ﳾ' => 'شي', 'ﳿ' => 'حى', 'ﴀ' => 'حي', 'ﴁ' => 'جى', 'ﴂ' => 'جي', 'ﴃ' => 'خى', 'ﴄ' => 'خي', 'ﴅ' => 'صى', 'ﴆ' => 'صي', 'ﴇ' => 'ضى', 'ﴈ' => 'ضي', 'ﴉ' => 'شج', 'ﴊ' => 'شح', 'ﴋ' => 'شخ', 'ﴌ' => 'شم', 'ﴍ' => 'شر', 'ﴎ' => 'سر', 'ﴏ' => 'صر', 'ﴐ' => 'ضر', 'ﴑ' => 'طى', 'ﴒ' => 'طي', 'ﴓ' => 'عى', 'ﴔ' => 'عي', 'ﴕ' => 'غى', 'ﴖ' => 'غي', 'ﴗ' => 'سى', 'ﴘ' => 'سي', 'ﴙ' => 'شى', 'ﴚ' => 'شي', 'ﴛ' => 'حى', 'ﴜ' => 'حي', 'ﴝ' => 'جى', 'ﴞ' => 'جي', 'ﴟ' => 'خى', 'ﴠ' => 'خي', 'ﴡ' => 'صى', 'ﴢ' => 'صي', 'ﴣ' => 'ضى', 'ﴤ' => 'ضي', 'ﴥ' => 'شج', 'ﴦ' => 'شح', 'ﴧ' => 'شخ', 'ﴨ' => 'شم', 'ﴩ' => 'شر', 'ﴪ' => 'سر', 'ﴫ' => 'صر', 'ﴬ' => 'ضر', 'ﴭ' => 'شج', 'ﴮ' => 'شح', 'ﴯ' => 'شخ', 'ﴰ' => 'شم', 'ﴱ' => 'سه', 'ﴲ' => 'شه', 'ﴳ' => 'طم', 'ﴴ' => 'سج', 'ﴵ' => 'سح', 'ﴶ' => 'سخ', 'ﴷ' => 'شج', 'ﴸ' => 'شح', 'ﴹ' => 'شخ', 'ﴺ' => 'طم', 'ﴻ' => 'ظم', 'ﴼ' => 'اً', 'ﴽ' => 'اً', 'ﵐ' => 'تجم', 'ﵑ' => 'تحج', 'ﵒ' => 'تحج', 'ﵓ' => 'تحم', 'ﵔ' => 'تخم', 'ﵕ' => 'تمج', 'ﵖ' => 'تمح', 'ﵗ' => 'تمخ', 'ﵘ' => 'جمح', 'ﵙ' => 'جمح', 'ﵚ' => 'حمي', 'ﵛ' => 'حمى', 'ﵜ' => 'سحج', 'ﵝ' => 'سجح', 'ﵞ' => 'سجى', 'ﵟ' => 'سمح', 'ﵠ' => 'سمح', 'ﵡ' => 'سمج', 'ﵢ' => 'سمم', 'ﵣ' => 'سمم', 'ﵤ' => 'صحح', 'ﵥ' => 'صحح', 'ﵦ' => 'صمم', 'ﵧ' => 'شحم', 'ﵨ' => 'شحم', 'ﵩ' => 'شجي', 'ﵪ' => 'شمخ', 'ﵫ' => 'شمخ', 'ﵬ' => 'شمم', 'ﵭ' => 'شمم', 'ﵮ' => 'ضحى', 'ﵯ' => 'ضخم', 'ﵰ' => 'ضخم', 'ﵱ' => 'طمح', 'ﵲ' => 'طمح', 'ﵳ' => 'طمم', 'ﵴ' => 'طمي', 'ﵵ' => 'عجم', 'ﵶ' => 'عمم', 'ﵷ' => 'عمم', 'ﵸ' => 'عمى', 'ﵹ' => 'غمم', 'ﵺ' => 'غمي', 'ﵻ' => 'غمى', 'ﵼ' => 'فخم', 'ﵽ' => 'فخم', 'ﵾ' => 'قمح', 'ﵿ' => 'قمم', 'ﶀ' => 'لحم', 'ﶁ' => 'لحي', 'ﶂ' => 'لحى', 'ﶃ' => 'لجج', 'ﶄ' => 'لجج', 'ﶅ' => 'لخم', 'ﶆ' => 'لخم', 'ﶇ' => 'لمح', 'ﶈ' => 'لمح', 'ﶉ' => 'محج', 'ﶊ' => 'محم', 'ﶋ' => 'محي', 'ﶌ' => 'مجح', 'ﶍ' => 'مجم', 'ﶎ' => 'مخج', 'ﶏ' => 'مخم', 'ﶒ' => 'مجخ', 'ﶓ' => 'همج', 'ﶔ' => 'همم', 'ﶕ' => 'نحم', 'ﶖ' => 'نحى', 'ﶗ' => 'نجم', 'ﶘ' => 'نجم', 'ﶙ' => 'نجى', 'ﶚ' => 'نمي', 'ﶛ' => 'نمى', 'ﶜ' => 'يمم', 'ﶝ' => 'يمم', 'ﶞ' => 'بخي', 'ﶟ' => 'تجي', 'ﶠ' => 'تجى', 'ﶡ' => 'تخي', 'ﶢ' => 'تخى', 'ﶣ' => 'تمي', 'ﶤ' => 'تمى', 'ﶥ' => 'جمي', 'ﶦ' => 'جحى', 'ﶧ' => 'جمى', 'ﶨ' => 'سخى', 'ﶩ' => 'صحي', 'ﶪ' => 'شحي', 'ﶫ' => 'ضحي', 'ﶬ' => 'لجي', 'ﶭ' => 'لمي', 'ﶮ' => 'يحي', 'ﶯ' => 'يجي', 'ﶰ' => 'يمي', 'ﶱ' => 'ممي', 'ﶲ' => 'قمي', 'ﶳ' => 'نحي', 'ﶴ' => 'قمح', 'ﶵ' => 'لحم', 'ﶶ' => 'عمي', 'ﶷ' => 'كمي', 'ﶸ' => 'نجح', 'ﶹ' => 'مخي', 'ﶺ' => 'لجم', 'ﶻ' => 'كمم', 'ﶼ' => 'لجم', 'ﶽ' => 'نجح', 'ﶾ' => 'جحي', 'ﶿ' => 'حجي', 'ﷀ' => 'مجي', 'ﷁ' => 'فمي', 'ﷂ' => 'بحي', 'ﷃ' => 'كمم', 'ﷄ' => 'عجم', 'ﷅ' => 'صمم', 'ﷆ' => 'سخي', 'ﷇ' => 'نجي', 'ﷰ' => 'صلے', 'ﷱ' => 'قلے', 'ﷲ' => 'الله', 'ﷳ' => 'اكبر', 'ﷴ' => 'محمد', 'ﷵ' => 'صلعم', 'ﷶ' => 'رسول', 'ﷷ' => 'عليه', 'ﷸ' => 'وسلم', 'ﷹ' => 'صلى', 'ﷺ' => 'صلى الله عليه وسلم', 'ﷻ' => 'جل جلاله', '﷼' => 'ریال', '︐' => ',', '︑' => '、', '︒' => '。', '︓' => ':', '︔' => ';', '︕' => '!', '︖' => '?', '︗' => '〖', '︘' => '〗', '︙' => '...', '︰' => '..', '︱' => '—', '︲' => '–', '︳' => '_', '︴' => '_', '︵' => '(', '︶' => ')', '︷' => '{', '︸' => '}', '︹' => '〔', '︺' => '〕', '︻' => '【', '︼' => '】', '︽' => '《', '︾' => '》', '︿' => '〈', '﹀' => '〉', '﹁' => '「', '﹂' => '」', '﹃' => '『', '﹄' => '』', '﹇' => '[', '﹈' => ']', '﹉' => ' ̅', '﹊' => ' ̅', '﹋' => ' ̅', '﹌' => ' ̅', '﹍' => '_', '﹎' => '_', '﹏' => '_', '﹐' => ',', '﹑' => '、', '﹒' => '.', '﹔' => ';', '﹕' => ':', '﹖' => '?', '﹗' => '!', '﹘' => '—', '﹙' => '(', '﹚' => ')', '﹛' => '{', '﹜' => '}', '﹝' => '〔', '﹞' => '〕', '﹟' => '#', '﹠' => '&', '﹡' => '*', '﹢' => '+', '﹣' => '-', '﹤' => '<', '﹥' => '>', '﹦' => '=', '﹨' => '\\', '﹩' => '$', '﹪' => '%', '﹫' => '@', 'ﹰ' => ' ً', 'ﹱ' => 'ـً', 'ﹲ' => ' ٌ', 'ﹴ' => ' ٍ', 'ﹶ' => ' َ', 'ﹷ' => 'ـَ', 'ﹸ' => ' ُ', 'ﹹ' => 'ـُ', 'ﹺ' => ' ِ', 'ﹻ' => 'ـِ', 'ﹼ' => ' ّ', 'ﹽ' => 'ـّ', 'ﹾ' => ' ْ', 'ﹿ' => 'ـْ', 'ﺀ' => 'ء', 'ﺁ' => 'آ', 'ﺂ' => 'آ', 'ﺃ' => 'أ', 'ﺄ' => 'أ', 'ﺅ' => 'ؤ', 'ﺆ' => 'ؤ', 'ﺇ' => 'إ', 'ﺈ' => 'إ', 'ﺉ' => 'ئ', 'ﺊ' => 'ئ', 'ﺋ' => 'ئ', 'ﺌ' => 'ئ', 'ﺍ' => 'ا', 'ﺎ' => 'ا', 'ﺏ' => 'ب', 'ﺐ' => 'ب', 'ﺑ' => 'ب', 'ﺒ' => 'ب', 'ﺓ' => 'ة', 'ﺔ' => 'ة', 'ﺕ' => 'ت', 'ﺖ' => 'ت', 'ﺗ' => 'ت', 'ﺘ' => 'ت', 'ﺙ' => 'ث', 'ﺚ' => 'ث', 'ﺛ' => 'ث', 'ﺜ' => 'ث', 'ﺝ' => 'ج', 'ﺞ' => 'ج', 'ﺟ' => 'ج', 'ﺠ' => 'ج', 'ﺡ' => 'ح', 'ﺢ' => 'ح', 'ﺣ' => 'ح', 'ﺤ' => 'ح', 'ﺥ' => 'خ', 'ﺦ' => 'خ', 'ﺧ' => 'خ', 'ﺨ' => 'خ', 'ﺩ' => 'د', 'ﺪ' => 'د', 'ﺫ' => 'ذ', 'ﺬ' => 'ذ', 'ﺭ' => 'ر', 'ﺮ' => 'ر', 'ﺯ' => 'ز', 'ﺰ' => 'ز', 'ﺱ' => 'س', 'ﺲ' => 'س', 'ﺳ' => 'س', 'ﺴ' => 'س', 'ﺵ' => 'ش', 'ﺶ' => 'ش', 'ﺷ' => 'ش', 'ﺸ' => 'ش', 'ﺹ' => 'ص', 'ﺺ' => 'ص', 'ﺻ' => 'ص', 'ﺼ' => 'ص', 'ﺽ' => 'ض', 'ﺾ' => 'ض', 'ﺿ' => 'ض', 'ﻀ' => 'ض', 'ﻁ' => 'ط', 'ﻂ' => 'ط', 'ﻃ' => 'ط', 'ﻄ' => 'ط', 'ﻅ' => 'ظ', 'ﻆ' => 'ظ', 'ﻇ' => 'ظ', 'ﻈ' => 'ظ', 'ﻉ' => 'ع', 'ﻊ' => 'ع', 'ﻋ' => 'ع', 'ﻌ' => 'ع', 'ﻍ' => 'غ', 'ﻎ' => 'غ', 'ﻏ' => 'غ', 'ﻐ' => 'غ', 'ﻑ' => 'ف', 'ﻒ' => 'ف', 'ﻓ' => 'ف', 'ﻔ' => 'ف', 'ﻕ' => 'ق', 'ﻖ' => 'ق', 'ﻗ' => 'ق', 'ﻘ' => 'ق', 'ﻙ' => 'ك', 'ﻚ' => 'ك', 'ﻛ' => 'ك', 'ﻜ' => 'ك', 'ﻝ' => 'ل', 'ﻞ' => 'ل', 'ﻟ' => 'ل', 'ﻠ' => 'ل', 'ﻡ' => 'م', 'ﻢ' => 'م', 'ﻣ' => 'م', 'ﻤ' => 'م', 'ﻥ' => 'ن', 'ﻦ' => 'ن', 'ﻧ' => 'ن', 'ﻨ' => 'ن', 'ﻩ' => 'ه', 'ﻪ' => 'ه', 'ﻫ' => 'ه', 'ﻬ' => 'ه', 'ﻭ' => 'و', 'ﻮ' => 'و', 'ﻯ' => 'ى', 'ﻰ' => 'ى', 'ﻱ' => 'ي', 'ﻲ' => 'ي', 'ﻳ' => 'ي', 'ﻴ' => 'ي', 'ﻵ' => 'لآ', 'ﻶ' => 'لآ', 'ﻷ' => 'لأ', 'ﻸ' => 'لأ', 'ﻹ' => 'لإ', 'ﻺ' => 'لإ', 'ﻻ' => 'لا', 'ﻼ' => 'لا', '!' => '!', '"' => '"', '#' => '#', '$' => '$', '%' => '%', '&' => '&', ''' => '\'', '(' => '(', ')' => ')', '*' => '*', '+' => '+', ',' => ',', '-' => '-', '.' => '.', '/' => '/', '0' => '0', '1' => '1', '2' => '2', '3' => '3', '4' => '4', '5' => '5', '6' => '6', '7' => '7', '8' => '8', '9' => '9', ':' => ':', ';' => ';', '<' => '<', '=' => '=', '>' => '>', '?' => '?', '@' => '@', 'A' => 'A', 'B' => 'B', 'C' => 'C', 'D' => 'D', 'E' => 'E', 'F' => 'F', 'G' => 'G', 'H' => 'H', 'I' => 'I', 'J' => 'J', 'K' => 'K', 'L' => 'L', 'M' => 'M', 'N' => 'N', 'O' => 'O', 'P' => 'P', 'Q' => 'Q', 'R' => 'R', 'S' => 'S', 'T' => 'T', 'U' => 'U', 'V' => 'V', 'W' => 'W', 'X' => 'X', 'Y' => 'Y', 'Z' => 'Z', '[' => '[', '\' => '\\', ']' => ']', '^' => '^', '_' => '_', '`' => '`', 'a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd', 'e' => 'e', 'f' => 'f', 'g' => 'g', 'h' => 'h', 'i' => 'i', 'j' => 'j', 'k' => 'k', 'l' => 'l', 'm' => 'm', 'n' => 'n', 'o' => 'o', 'p' => 'p', 'q' => 'q', 'r' => 'r', 's' => 's', 't' => 't', 'u' => 'u', 'v' => 'v', 'w' => 'w', 'x' => 'x', 'y' => 'y', 'z' => 'z', '{' => '{', '|' => '|', '}' => '}', '~' => '~', '⦅' => '⦅', '⦆' => '⦆', '。' => '。', '「' => '「', '」' => '」', '、' => '、', '・' => '・', 'ヲ' => 'ヲ', 'ァ' => 'ァ', 'ィ' => 'ィ', 'ゥ' => 'ゥ', 'ェ' => 'ェ', 'ォ' => 'ォ', 'ャ' => 'ャ', 'ュ' => 'ュ', 'ョ' => 'ョ', 'ッ' => 'ッ', 'ー' => 'ー', 'ア' => 'ア', 'イ' => 'イ', 'ウ' => 'ウ', 'エ' => 'エ', 'オ' => 'オ', 'カ' => 'カ', 'キ' => 'キ', 'ク' => 'ク', 'ケ' => 'ケ', 'コ' => 'コ', 'サ' => 'サ', 'シ' => 'シ', 'ス' => 'ス', 'セ' => 'セ', 'ソ' => 'ソ', 'タ' => 'タ', 'チ' => 'チ', 'ツ' => 'ツ', 'テ' => 'テ', 'ト' => 'ト', 'ナ' => 'ナ', 'ニ' => 'ニ', 'ヌ' => 'ヌ', 'ネ' => 'ネ', 'ノ' => 'ノ', 'ハ' => 'ハ', 'ヒ' => 'ヒ', 'フ' => 'フ', 'ヘ' => 'ヘ', 'ホ' => 'ホ', 'マ' => 'マ', 'ミ' => 'ミ', 'ム' => 'ム', 'メ' => 'メ', 'モ' => 'モ', 'ヤ' => 'ヤ', 'ユ' => 'ユ', 'ヨ' => 'ヨ', 'ラ' => 'ラ', 'リ' => 'リ', 'ル' => 'ル', 'レ' => 'レ', 'ロ' => 'ロ', 'ワ' => 'ワ', 'ン' => 'ン', '゙' => '゙', '゚' => '゚', 'ᅠ' => 'ᅠ', 'ᄀ' => 'ᄀ', 'ᄁ' => 'ᄁ', 'ᆪ' => 'ᆪ', 'ᄂ' => 'ᄂ', 'ᆬ' => 'ᆬ', 'ᆭ' => 'ᆭ', 'ᄃ' => 'ᄃ', 'ᄄ' => 'ᄄ', 'ᄅ' => 'ᄅ', 'ᆰ' => 'ᆰ', 'ᆱ' => 'ᆱ', 'ᆲ' => 'ᆲ', 'ᆳ' => 'ᆳ', 'ᆴ' => 'ᆴ', 'ᆵ' => 'ᆵ', 'ᄚ' => 'ᄚ', 'ᄆ' => 'ᄆ', 'ᄇ' => 'ᄇ', 'ᄈ' => 'ᄈ', 'ᄡ' => 'ᄡ', 'ᄉ' => 'ᄉ', 'ᄊ' => 'ᄊ', 'ᄋ' => 'ᄋ', 'ᄌ' => 'ᄌ', 'ᄍ' => 'ᄍ', 'ᄎ' => 'ᄎ', 'ᄏ' => 'ᄏ', 'ᄐ' => 'ᄐ', 'ᄑ' => 'ᄑ', 'ᄒ' => 'ᄒ', 'ᅡ' => 'ᅡ', 'ᅢ' => 'ᅢ', 'ᅣ' => 'ᅣ', 'ᅤ' => 'ᅤ', 'ᅥ' => 'ᅥ', 'ᅦ' => 'ᅦ', 'ᅧ' => 'ᅧ', 'ᅨ' => 'ᅨ', 'ᅩ' => 'ᅩ', 'ᅪ' => 'ᅪ', 'ᅫ' => 'ᅫ', 'ᅬ' => 'ᅬ', 'ᅭ' => 'ᅭ', 'ᅮ' => 'ᅮ', 'ᅯ' => 'ᅯ', 'ᅰ' => 'ᅰ', 'ᅱ' => 'ᅱ', 'ᅲ' => 'ᅲ', 'ᅳ' => 'ᅳ', 'ᅴ' => 'ᅴ', 'ᅵ' => 'ᅵ', '¢' => '¢', '£' => '£', '¬' => '¬', ' ̄' => ' ̄', '¦' => '¦', '¥' => '¥', '₩' => '₩', '│' => '│', '←' => '←', '↑' => '↑', '→' => '→', '↓' => '↓', '■' => '■', '○' => '○', '𝐀' => 'A', '𝐁' => 'B', '𝐂' => 'C', '𝐃' => 'D', '𝐄' => 'E', '𝐅' => 'F', '𝐆' => 'G', '𝐇' => 'H', '𝐈' => 'I', '𝐉' => 'J', '𝐊' => 'K', '𝐋' => 'L', '𝐌' => 'M', '𝐍' => 'N', '𝐎' => 'O', '𝐏' => 'P', '𝐐' => 'Q', '𝐑' => 'R', '𝐒' => 'S', '𝐓' => 'T', '𝐔' => 'U', '𝐕' => 'V', '𝐖' => 'W', '𝐗' => 'X', '𝐘' => 'Y', '𝐙' => 'Z', '𝐚' => 'a', '𝐛' => 'b', '𝐜' => 'c', '𝐝' => 'd', '𝐞' => 'e', '𝐟' => 'f', '𝐠' => 'g', '𝐡' => 'h', '𝐢' => 'i', '𝐣' => 'j', '𝐤' => 'k', '𝐥' => 'l', '𝐦' => 'm', '𝐧' => 'n', '𝐨' => 'o', '𝐩' => 'p', '𝐪' => 'q', '𝐫' => 'r', '𝐬' => 's', '𝐭' => 't', '𝐮' => 'u', '𝐯' => 'v', '𝐰' => 'w', '𝐱' => 'x', '𝐲' => 'y', '𝐳' => 'z', '𝐴' => 'A', '𝐵' => 'B', '𝐶' => 'C', '𝐷' => 'D', '𝐸' => 'E', '𝐹' => 'F', '𝐺' => 'G', '𝐻' => 'H', '𝐼' => 'I', '𝐽' => 'J', '𝐾' => 'K', '𝐿' => 'L', '𝑀' => 'M', '𝑁' => 'N', '𝑂' => 'O', '𝑃' => 'P', '𝑄' => 'Q', '𝑅' => 'R', '𝑆' => 'S', '𝑇' => 'T', '𝑈' => 'U', '𝑉' => 'V', '𝑊' => 'W', '𝑋' => 'X', '𝑌' => 'Y', '𝑍' => 'Z', '𝑎' => 'a', '𝑏' => 'b', '𝑐' => 'c', '𝑑' => 'd', '𝑒' => 'e', '𝑓' => 'f', '𝑔' => 'g', '𝑖' => 'i', '𝑗' => 'j', '𝑘' => 'k', '𝑙' => 'l', '𝑚' => 'm', '𝑛' => 'n', '𝑜' => 'o', '𝑝' => 'p', '𝑞' => 'q', '𝑟' => 'r', '𝑠' => 's', '𝑡' => 't', '𝑢' => 'u', '𝑣' => 'v', '𝑤' => 'w', '𝑥' => 'x', '𝑦' => 'y', '𝑧' => 'z', '𝑨' => 'A', '𝑩' => 'B', '𝑪' => 'C', '𝑫' => 'D', '𝑬' => 'E', '𝑭' => 'F', '𝑮' => 'G', '𝑯' => 'H', '𝑰' => 'I', '𝑱' => 'J', '𝑲' => 'K', '𝑳' => 'L', '𝑴' => 'M', '𝑵' => 'N', '𝑶' => 'O', '𝑷' => 'P', '𝑸' => 'Q', '𝑹' => 'R', '𝑺' => 'S', '𝑻' => 'T', '𝑼' => 'U', '𝑽' => 'V', '𝑾' => 'W', '𝑿' => 'X', '𝒀' => 'Y', '𝒁' => 'Z', '𝒂' => 'a', '𝒃' => 'b', '𝒄' => 'c', '𝒅' => 'd', '𝒆' => 'e', '𝒇' => 'f', '𝒈' => 'g', '𝒉' => 'h', '𝒊' => 'i', '𝒋' => 'j', '𝒌' => 'k', '𝒍' => 'l', '𝒎' => 'm', '𝒏' => 'n', '𝒐' => 'o', '𝒑' => 'p', '𝒒' => 'q', '𝒓' => 'r', '𝒔' => 's', '𝒕' => 't', '𝒖' => 'u', '𝒗' => 'v', '𝒘' => 'w', '𝒙' => 'x', '𝒚' => 'y', '𝒛' => 'z', '𝒜' => 'A', '𝒞' => 'C', '𝒟' => 'D', '𝒢' => 'G', '𝒥' => 'J', '𝒦' => 'K', '𝒩' => 'N', '𝒪' => 'O', '𝒫' => 'P', '𝒬' => 'Q', '𝒮' => 'S', '𝒯' => 'T', '𝒰' => 'U', '𝒱' => 'V', '𝒲' => 'W', '𝒳' => 'X', '𝒴' => 'Y', '𝒵' => 'Z', '𝒶' => 'a', '𝒷' => 'b', '𝒸' => 'c', '𝒹' => 'd', '𝒻' => 'f', '𝒽' => 'h', '𝒾' => 'i', '𝒿' => 'j', '𝓀' => 'k', '𝓁' => 'l', '𝓂' => 'm', '𝓃' => 'n', '𝓅' => 'p', '𝓆' => 'q', '𝓇' => 'r', '𝓈' => 's', '𝓉' => 't', '𝓊' => 'u', '𝓋' => 'v', '𝓌' => 'w', '𝓍' => 'x', '𝓎' => 'y', '𝓏' => 'z', '𝓐' => 'A', '𝓑' => 'B', '𝓒' => 'C', '𝓓' => 'D', '𝓔' => 'E', '𝓕' => 'F', '𝓖' => 'G', '𝓗' => 'H', '𝓘' => 'I', '𝓙' => 'J', '𝓚' => 'K', '𝓛' => 'L', '𝓜' => 'M', '𝓝' => 'N', '𝓞' => 'O', '𝓟' => 'P', '𝓠' => 'Q', '𝓡' => 'R', '𝓢' => 'S', '𝓣' => 'T', '𝓤' => 'U', '𝓥' => 'V', '𝓦' => 'W', '𝓧' => 'X', '𝓨' => 'Y', '𝓩' => 'Z', '𝓪' => 'a', '𝓫' => 'b', '𝓬' => 'c', '𝓭' => 'd', '𝓮' => 'e', '𝓯' => 'f', '𝓰' => 'g', '𝓱' => 'h', '𝓲' => 'i', '𝓳' => 'j', '𝓴' => 'k', '𝓵' => 'l', '𝓶' => 'm', '𝓷' => 'n', '𝓸' => 'o', '𝓹' => 'p', '𝓺' => 'q', '𝓻' => 'r', '𝓼' => 's', '𝓽' => 't', '𝓾' => 'u', '𝓿' => 'v', '𝔀' => 'w', '𝔁' => 'x', '𝔂' => 'y', '𝔃' => 'z', '𝔄' => 'A', '𝔅' => 'B', '𝔇' => 'D', '𝔈' => 'E', '𝔉' => 'F', '𝔊' => 'G', '𝔍' => 'J', '𝔎' => 'K', '𝔏' => 'L', '𝔐' => 'M', '𝔑' => 'N', '𝔒' => 'O', '𝔓' => 'P', '𝔔' => 'Q', '𝔖' => 'S', '𝔗' => 'T', '𝔘' => 'U', '𝔙' => 'V', '𝔚' => 'W', '𝔛' => 'X', '𝔜' => 'Y', '𝔞' => 'a', '𝔟' => 'b', '𝔠' => 'c', '𝔡' => 'd', '𝔢' => 'e', '𝔣' => 'f', '𝔤' => 'g', '𝔥' => 'h', '𝔦' => 'i', '𝔧' => 'j', '𝔨' => 'k', '𝔩' => 'l', '𝔪' => 'm', '𝔫' => 'n', '𝔬' => 'o', '𝔭' => 'p', '𝔮' => 'q', '𝔯' => 'r', '𝔰' => 's', '𝔱' => 't', '𝔲' => 'u', '𝔳' => 'v', '𝔴' => 'w', '𝔵' => 'x', '𝔶' => 'y', '𝔷' => 'z', '𝔸' => 'A', '𝔹' => 'B', '𝔻' => 'D', '𝔼' => 'E', '𝔽' => 'F', '𝔾' => 'G', '𝕀' => 'I', '𝕁' => 'J', '𝕂' => 'K', '𝕃' => 'L', '𝕄' => 'M', '𝕆' => 'O', '𝕊' => 'S', '𝕋' => 'T', '𝕌' => 'U', '𝕍' => 'V', '𝕎' => 'W', '𝕏' => 'X', '𝕐' => 'Y', '𝕒' => 'a', '𝕓' => 'b', '𝕔' => 'c', '𝕕' => 'd', '𝕖' => 'e', '𝕗' => 'f', '𝕘' => 'g', '𝕙' => 'h', '𝕚' => 'i', '𝕛' => 'j', '𝕜' => 'k', '𝕝' => 'l', '𝕞' => 'm', '𝕟' => 'n', '𝕠' => 'o', '𝕡' => 'p', '𝕢' => 'q', '𝕣' => 'r', '𝕤' => 's', '𝕥' => 't', '𝕦' => 'u', '𝕧' => 'v', '𝕨' => 'w', '𝕩' => 'x', '𝕪' => 'y', '𝕫' => 'z', '𝕬' => 'A', '𝕭' => 'B', '𝕮' => 'C', '𝕯' => 'D', '𝕰' => 'E', '𝕱' => 'F', '𝕲' => 'G', '𝕳' => 'H', '𝕴' => 'I', '𝕵' => 'J', '𝕶' => 'K', '𝕷' => 'L', '𝕸' => 'M', '𝕹' => 'N', '𝕺' => 'O', '𝕻' => 'P', '𝕼' => 'Q', '𝕽' => 'R', '𝕾' => 'S', '𝕿' => 'T', '𝖀' => 'U', '𝖁' => 'V', '𝖂' => 'W', '𝖃' => 'X', '𝖄' => 'Y', '𝖅' => 'Z', '𝖆' => 'a', '𝖇' => 'b', '𝖈' => 'c', '𝖉' => 'd', '𝖊' => 'e', '𝖋' => 'f', '𝖌' => 'g', '𝖍' => 'h', '𝖎' => 'i', '𝖏' => 'j', '𝖐' => 'k', '𝖑' => 'l', '𝖒' => 'm', '𝖓' => 'n', '𝖔' => 'o', '𝖕' => 'p', '𝖖' => 'q', '𝖗' => 'r', '𝖘' => 's', '𝖙' => 't', '𝖚' => 'u', '𝖛' => 'v', '𝖜' => 'w', '𝖝' => 'x', '𝖞' => 'y', '𝖟' => 'z', '𝖠' => 'A', '𝖡' => 'B', '𝖢' => 'C', '𝖣' => 'D', '𝖤' => 'E', '𝖥' => 'F', '𝖦' => 'G', '𝖧' => 'H', '𝖨' => 'I', '𝖩' => 'J', '𝖪' => 'K', '𝖫' => 'L', '𝖬' => 'M', '𝖭' => 'N', '𝖮' => 'O', '𝖯' => 'P', '𝖰' => 'Q', '𝖱' => 'R', '𝖲' => 'S', '𝖳' => 'T', '𝖴' => 'U', '𝖵' => 'V', '𝖶' => 'W', '𝖷' => 'X', '𝖸' => 'Y', '𝖹' => 'Z', '𝖺' => 'a', '𝖻' => 'b', '𝖼' => 'c', '𝖽' => 'd', '𝖾' => 'e', '𝖿' => 'f', '𝗀' => 'g', '𝗁' => 'h', '𝗂' => 'i', '𝗃' => 'j', '𝗄' => 'k', '𝗅' => 'l', '𝗆' => 'm', '𝗇' => 'n', '𝗈' => 'o', '𝗉' => 'p', '𝗊' => 'q', '𝗋' => 'r', '𝗌' => 's', '𝗍' => 't', '𝗎' => 'u', '𝗏' => 'v', '𝗐' => 'w', '𝗑' => 'x', '𝗒' => 'y', '𝗓' => 'z', '𝗔' => 'A', '𝗕' => 'B', '𝗖' => 'C', '𝗗' => 'D', '𝗘' => 'E', '𝗙' => 'F', '𝗚' => 'G', '𝗛' => 'H', '𝗜' => 'I', '𝗝' => 'J', '𝗞' => 'K', '𝗟' => 'L', '𝗠' => 'M', '𝗡' => 'N', '𝗢' => 'O', '𝗣' => 'P', '𝗤' => 'Q', '𝗥' => 'R', '𝗦' => 'S', '𝗧' => 'T', '𝗨' => 'U', '𝗩' => 'V', '𝗪' => 'W', '𝗫' => 'X', '𝗬' => 'Y', '𝗭' => 'Z', '𝗮' => 'a', '𝗯' => 'b', '𝗰' => 'c', '𝗱' => 'd', '𝗲' => 'e', '𝗳' => 'f', '𝗴' => 'g', '𝗵' => 'h', '𝗶' => 'i', '𝗷' => 'j', '𝗸' => 'k', '𝗹' => 'l', '𝗺' => 'm', '𝗻' => 'n', '𝗼' => 'o', '𝗽' => 'p', '𝗾' => 'q', '𝗿' => 'r', '𝘀' => 's', '𝘁' => 't', '𝘂' => 'u', '𝘃' => 'v', '𝘄' => 'w', '𝘅' => 'x', '𝘆' => 'y', '𝘇' => 'z', '𝘈' => 'A', '𝘉' => 'B', '𝘊' => 'C', '𝘋' => 'D', '𝘌' => 'E', '𝘍' => 'F', '𝘎' => 'G', '𝘏' => 'H', '𝘐' => 'I', '𝘑' => 'J', '𝘒' => 'K', '𝘓' => 'L', '𝘔' => 'M', '𝘕' => 'N', '𝘖' => 'O', '𝘗' => 'P', '𝘘' => 'Q', '𝘙' => 'R', '𝘚' => 'S', '𝘛' => 'T', '𝘜' => 'U', '𝘝' => 'V', '𝘞' => 'W', '𝘟' => 'X', '𝘠' => 'Y', '𝘡' => 'Z', '𝘢' => 'a', '𝘣' => 'b', '𝘤' => 'c', '𝘥' => 'd', '𝘦' => 'e', '𝘧' => 'f', '𝘨' => 'g', '𝘩' => 'h', '𝘪' => 'i', '𝘫' => 'j', '𝘬' => 'k', '𝘭' => 'l', '𝘮' => 'm', '𝘯' => 'n', '𝘰' => 'o', '𝘱' => 'p', '𝘲' => 'q', '𝘳' => 'r', '𝘴' => 's', '𝘵' => 't', '𝘶' => 'u', '𝘷' => 'v', '𝘸' => 'w', '𝘹' => 'x', '𝘺' => 'y', '𝘻' => 'z', '𝘼' => 'A', '𝘽' => 'B', '𝘾' => 'C', '𝘿' => 'D', '𝙀' => 'E', '𝙁' => 'F', '𝙂' => 'G', '𝙃' => 'H', '𝙄' => 'I', '𝙅' => 'J', '𝙆' => 'K', '𝙇' => 'L', '𝙈' => 'M', '𝙉' => 'N', '𝙊' => 'O', '𝙋' => 'P', '𝙌' => 'Q', '𝙍' => 'R', '𝙎' => 'S', '𝙏' => 'T', '𝙐' => 'U', '𝙑' => 'V', '𝙒' => 'W', '𝙓' => 'X', '𝙔' => 'Y', '𝙕' => 'Z', '𝙖' => 'a', '𝙗' => 'b', '𝙘' => 'c', '𝙙' => 'd', '𝙚' => 'e', '𝙛' => 'f', '𝙜' => 'g', '𝙝' => 'h', '𝙞' => 'i', '𝙟' => 'j', '𝙠' => 'k', '𝙡' => 'l', '𝙢' => 'm', '𝙣' => 'n', '𝙤' => 'o', '𝙥' => 'p', '𝙦' => 'q', '𝙧' => 'r', '𝙨' => 's', '𝙩' => 't', '𝙪' => 'u', '𝙫' => 'v', '𝙬' => 'w', '𝙭' => 'x', '𝙮' => 'y', '𝙯' => 'z', '𝙰' => 'A', '𝙱' => 'B', '𝙲' => 'C', '𝙳' => 'D', '𝙴' => 'E', '𝙵' => 'F', '𝙶' => 'G', '𝙷' => 'H', '𝙸' => 'I', '𝙹' => 'J', '𝙺' => 'K', '𝙻' => 'L', '𝙼' => 'M', '𝙽' => 'N', '𝙾' => 'O', '𝙿' => 'P', '𝚀' => 'Q', '𝚁' => 'R', '𝚂' => 'S', '𝚃' => 'T', '𝚄' => 'U', '𝚅' => 'V', '𝚆' => 'W', '𝚇' => 'X', '𝚈' => 'Y', '𝚉' => 'Z', '𝚊' => 'a', '𝚋' => 'b', '𝚌' => 'c', '𝚍' => 'd', '𝚎' => 'e', '𝚏' => 'f', '𝚐' => 'g', '𝚑' => 'h', '𝚒' => 'i', '𝚓' => 'j', '𝚔' => 'k', '𝚕' => 'l', '𝚖' => 'm', '𝚗' => 'n', '𝚘' => 'o', '𝚙' => 'p', '𝚚' => 'q', '𝚛' => 'r', '𝚜' => 's', '𝚝' => 't', '𝚞' => 'u', '𝚟' => 'v', '𝚠' => 'w', '𝚡' => 'x', '𝚢' => 'y', '𝚣' => 'z', '𝚤' => 'ı', '𝚥' => 'ȷ', '𝚨' => 'Α', '𝚩' => 'Β', '𝚪' => 'Γ', '𝚫' => 'Δ', '𝚬' => 'Ε', '𝚭' => 'Ζ', '𝚮' => 'Η', '𝚯' => 'Θ', '𝚰' => 'Ι', '𝚱' => 'Κ', '𝚲' => 'Λ', '𝚳' => 'Μ', '𝚴' => 'Ν', '𝚵' => 'Ξ', '𝚶' => 'Ο', '𝚷' => 'Π', '𝚸' => 'Ρ', '𝚹' => 'Θ', '𝚺' => 'Σ', '𝚻' => 'Τ', '𝚼' => 'Υ', '𝚽' => 'Φ', '𝚾' => 'Χ', '𝚿' => 'Ψ', '𝛀' => 'Ω', '𝛁' => '∇', '𝛂' => 'α', '𝛃' => 'β', '𝛄' => 'γ', '𝛅' => 'δ', '𝛆' => 'ε', '𝛇' => 'ζ', '𝛈' => 'η', '𝛉' => 'θ', '𝛊' => 'ι', '𝛋' => 'κ', '𝛌' => 'λ', '𝛍' => 'μ', '𝛎' => 'ν', '𝛏' => 'ξ', '𝛐' => 'ο', '𝛑' => 'π', '𝛒' => 'ρ', '𝛓' => 'ς', '𝛔' => 'σ', '𝛕' => 'τ', '𝛖' => 'υ', '𝛗' => 'φ', '𝛘' => 'χ', '𝛙' => 'ψ', '𝛚' => 'ω', '𝛛' => '∂', '𝛜' => 'ε', '𝛝' => 'θ', '𝛞' => 'κ', '𝛟' => 'φ', '𝛠' => 'ρ', '𝛡' => 'π', '𝛢' => 'Α', '𝛣' => 'Β', '𝛤' => 'Γ', '𝛥' => 'Δ', '𝛦' => 'Ε', '𝛧' => 'Ζ', '𝛨' => 'Η', '𝛩' => 'Θ', '𝛪' => 'Ι', '𝛫' => 'Κ', '𝛬' => 'Λ', '𝛭' => 'Μ', '𝛮' => 'Ν', '𝛯' => 'Ξ', '𝛰' => 'Ο', '𝛱' => 'Π', '𝛲' => 'Ρ', '𝛳' => 'Θ', '𝛴' => 'Σ', '𝛵' => 'Τ', '𝛶' => 'Υ', '𝛷' => 'Φ', '𝛸' => 'Χ', '𝛹' => 'Ψ', '𝛺' => 'Ω', '𝛻' => '∇', '𝛼' => 'α', '𝛽' => 'β', '𝛾' => 'γ', '𝛿' => 'δ', '𝜀' => 'ε', '𝜁' => 'ζ', '𝜂' => 'η', '𝜃' => 'θ', '𝜄' => 'ι', '𝜅' => 'κ', '𝜆' => 'λ', '𝜇' => 'μ', '𝜈' => 'ν', '𝜉' => 'ξ', '𝜊' => 'ο', '𝜋' => 'π', '𝜌' => 'ρ', '𝜍' => 'ς', '𝜎' => 'σ', '𝜏' => 'τ', '𝜐' => 'υ', '𝜑' => 'φ', '𝜒' => 'χ', '𝜓' => 'ψ', '𝜔' => 'ω', '𝜕' => '∂', '𝜖' => 'ε', '𝜗' => 'θ', '𝜘' => 'κ', '𝜙' => 'φ', '𝜚' => 'ρ', '𝜛' => 'π', '𝜜' => 'Α', '𝜝' => 'Β', '𝜞' => 'Γ', '𝜟' => 'Δ', '𝜠' => 'Ε', '𝜡' => 'Ζ', '𝜢' => 'Η', '𝜣' => 'Θ', '𝜤' => 'Ι', '𝜥' => 'Κ', '𝜦' => 'Λ', '𝜧' => 'Μ', '𝜨' => 'Ν', '𝜩' => 'Ξ', '𝜪' => 'Ο', '𝜫' => 'Π', '𝜬' => 'Ρ', '𝜭' => 'Θ', '𝜮' => 'Σ', '𝜯' => 'Τ', '𝜰' => 'Υ', '𝜱' => 'Φ', '𝜲' => 'Χ', '𝜳' => 'Ψ', '𝜴' => 'Ω', '𝜵' => '∇', '𝜶' => 'α', '𝜷' => 'β', '𝜸' => 'γ', '𝜹' => 'δ', '𝜺' => 'ε', '𝜻' => 'ζ', '𝜼' => 'η', '𝜽' => 'θ', '𝜾' => 'ι', '𝜿' => 'κ', '𝝀' => 'λ', '𝝁' => 'μ', '𝝂' => 'ν', '𝝃' => 'ξ', '𝝄' => 'ο', '𝝅' => 'π', '𝝆' => 'ρ', '𝝇' => 'ς', '𝝈' => 'σ', '𝝉' => 'τ', '𝝊' => 'υ', '𝝋' => 'φ', '𝝌' => 'χ', '𝝍' => 'ψ', '𝝎' => 'ω', '𝝏' => '∂', '𝝐' => 'ε', '𝝑' => 'θ', '𝝒' => 'κ', '𝝓' => 'φ', '𝝔' => 'ρ', '𝝕' => 'π', '𝝖' => 'Α', '𝝗' => 'Β', '𝝘' => 'Γ', '𝝙' => 'Δ', '𝝚' => 'Ε', '𝝛' => 'Ζ', '𝝜' => 'Η', '𝝝' => 'Θ', '𝝞' => 'Ι', '𝝟' => 'Κ', '𝝠' => 'Λ', '𝝡' => 'Μ', '𝝢' => 'Ν', '𝝣' => 'Ξ', '𝝤' => 'Ο', '𝝥' => 'Π', '𝝦' => 'Ρ', '𝝧' => 'Θ', '𝝨' => 'Σ', '𝝩' => 'Τ', '𝝪' => 'Υ', '𝝫' => 'Φ', '𝝬' => 'Χ', '𝝭' => 'Ψ', '𝝮' => 'Ω', '𝝯' => '∇', '𝝰' => 'α', '𝝱' => 'β', '𝝲' => 'γ', '𝝳' => 'δ', '𝝴' => 'ε', '𝝵' => 'ζ', '𝝶' => 'η', '𝝷' => 'θ', '𝝸' => 'ι', '𝝹' => 'κ', '𝝺' => 'λ', '𝝻' => 'μ', '𝝼' => 'ν', '𝝽' => 'ξ', '𝝾' => 'ο', '𝝿' => 'π', '𝞀' => 'ρ', '𝞁' => 'ς', '𝞂' => 'σ', '𝞃' => 'τ', '𝞄' => 'υ', '𝞅' => 'φ', '𝞆' => 'χ', '𝞇' => 'ψ', '𝞈' => 'ω', '𝞉' => '∂', '𝞊' => 'ε', '𝞋' => 'θ', '𝞌' => 'κ', '𝞍' => 'φ', '𝞎' => 'ρ', '𝞏' => 'π', '𝞐' => 'Α', '𝞑' => 'Β', '𝞒' => 'Γ', '𝞓' => 'Δ', '𝞔' => 'Ε', '𝞕' => 'Ζ', '𝞖' => 'Η', '𝞗' => 'Θ', '𝞘' => 'Ι', '𝞙' => 'Κ', '𝞚' => 'Λ', '𝞛' => 'Μ', '𝞜' => 'Ν', '𝞝' => 'Ξ', '𝞞' => 'Ο', '𝞟' => 'Π', '𝞠' => 'Ρ', '𝞡' => 'Θ', '𝞢' => 'Σ', '𝞣' => 'Τ', '𝞤' => 'Υ', '𝞥' => 'Φ', '𝞦' => 'Χ', '𝞧' => 'Ψ', '𝞨' => 'Ω', '𝞩' => '∇', '𝞪' => 'α', '𝞫' => 'β', '𝞬' => 'γ', '𝞭' => 'δ', '𝞮' => 'ε', '𝞯' => 'ζ', '𝞰' => 'η', '𝞱' => 'θ', '𝞲' => 'ι', '𝞳' => 'κ', '𝞴' => 'λ', '𝞵' => 'μ', '𝞶' => 'ν', '𝞷' => 'ξ', '𝞸' => 'ο', '𝞹' => 'π', '𝞺' => 'ρ', '𝞻' => 'ς', '𝞼' => 'σ', '𝞽' => 'τ', '𝞾' => 'υ', '𝞿' => 'φ', '𝟀' => 'χ', '𝟁' => 'ψ', '𝟂' => 'ω', '𝟃' => '∂', '𝟄' => 'ε', '𝟅' => 'θ', '𝟆' => 'κ', '𝟇' => 'φ', '𝟈' => 'ρ', '𝟉' => 'π', '𝟊' => 'Ϝ', '𝟋' => 'ϝ', '𝟎' => '0', '𝟏' => '1', '𝟐' => '2', '𝟑' => '3', '𝟒' => '4', '𝟓' => '5', '𝟔' => '6', '𝟕' => '7', '𝟖' => '8', '𝟗' => '9', '𝟘' => '0', '𝟙' => '1', '𝟚' => '2', '𝟛' => '3', '𝟜' => '4', '𝟝' => '5', '𝟞' => '6', '𝟟' => '7', '𝟠' => '8', '𝟡' => '9', '𝟢' => '0', '𝟣' => '1', '𝟤' => '2', '𝟥' => '3', '𝟦' => '4', '𝟧' => '5', '𝟨' => '6', '𝟩' => '7', '𝟪' => '8', '𝟫' => '9', '𝟬' => '0', '𝟭' => '1', '𝟮' => '2', '𝟯' => '3', '𝟰' => '4', '𝟱' => '5', '𝟲' => '6', '𝟳' => '7', '𝟴' => '8', '𝟵' => '9', '𝟶' => '0', '𝟷' => '1', '𝟸' => '2', '𝟹' => '3', '𝟺' => '4', '𝟻' => '5', '𝟼' => '6', '𝟽' => '7', '𝟾' => '8', '𝟿' => '9', '𞸀' => 'ا', '𞸁' => 'ب', '𞸂' => 'ج', '𞸃' => 'د', '𞸅' => 'و', '𞸆' => 'ز', '𞸇' => 'ح', '𞸈' => 'ط', '𞸉' => 'ي', '𞸊' => 'ك', '𞸋' => 'ل', '𞸌' => 'م', '𞸍' => 'ن', '𞸎' => 'س', '𞸏' => 'ع', '𞸐' => 'ف', '𞸑' => 'ص', '𞸒' => 'ق', '𞸓' => 'ر', '𞸔' => 'ش', '𞸕' => 'ت', '𞸖' => 'ث', '𞸗' => 'خ', '𞸘' => 'ذ', '𞸙' => 'ض', '𞸚' => 'ظ', '𞸛' => 'غ', '𞸜' => 'ٮ', '𞸝' => 'ں', '𞸞' => 'ڡ', '𞸟' => 'ٯ', '𞸡' => 'ب', '𞸢' => 'ج', '𞸤' => 'ه', '𞸧' => 'ح', '𞸩' => 'ي', '𞸪' => 'ك', '𞸫' => 'ل', '𞸬' => 'م', '𞸭' => 'ن', '𞸮' => 'س', '𞸯' => 'ع', '𞸰' => 'ف', '𞸱' => 'ص', '𞸲' => 'ق', '𞸴' => 'ش', '𞸵' => 'ت', '𞸶' => 'ث', '𞸷' => 'خ', '𞸹' => 'ض', '𞸻' => 'غ', '𞹂' => 'ج', '𞹇' => 'ح', '𞹉' => 'ي', '𞹋' => 'ل', '𞹍' => 'ن', '𞹎' => 'س', '𞹏' => 'ع', '𞹑' => 'ص', '𞹒' => 'ق', '𞹔' => 'ش', '𞹗' => 'خ', '𞹙' => 'ض', '𞹛' => 'غ', '𞹝' => 'ں', '𞹟' => 'ٯ', '𞹡' => 'ب', '𞹢' => 'ج', '𞹤' => 'ه', '𞹧' => 'ح', '𞹨' => 'ط', '𞹩' => 'ي', '𞹪' => 'ك', '𞹬' => 'م', '𞹭' => 'ن', '𞹮' => 'س', '𞹯' => 'ع', '𞹰' => 'ف', '𞹱' => 'ص', '𞹲' => 'ق', '𞹴' => 'ش', '𞹵' => 'ت', '𞹶' => 'ث', '𞹷' => 'خ', '𞹹' => 'ض', '𞹺' => 'ظ', '𞹻' => 'غ', '𞹼' => 'ٮ', '𞹾' => 'ڡ', '𞺀' => 'ا', '𞺁' => 'ب', '𞺂' => 'ج', '𞺃' => 'د', '𞺄' => 'ه', '𞺅' => 'و', '𞺆' => 'ز', '𞺇' => 'ح', '𞺈' => 'ط', '𞺉' => 'ي', '𞺋' => 'ل', '𞺌' => 'م', '𞺍' => 'ن', '𞺎' => 'س', '𞺏' => 'ع', '𞺐' => 'ف', '𞺑' => 'ص', '𞺒' => 'ق', '𞺓' => 'ر', '𞺔' => 'ش', '𞺕' => 'ت', '𞺖' => 'ث', '𞺗' => 'خ', '𞺘' => 'ذ', '𞺙' => 'ض', '𞺚' => 'ظ', '𞺛' => 'غ', '𞺡' => 'ب', '𞺢' => 'ج', '𞺣' => 'د', '𞺥' => 'و', '𞺦' => 'ز', '𞺧' => 'ح', '𞺨' => 'ط', '𞺩' => 'ي', '𞺫' => 'ل', '𞺬' => 'م', '𞺭' => 'ن', '𞺮' => 'س', '𞺯' => 'ع', '𞺰' => 'ف', '𞺱' => 'ص', '𞺲' => 'ق', '𞺳' => 'ر', '𞺴' => 'ش', '𞺵' => 'ت', '𞺶' => 'ث', '𞺷' => 'خ', '𞺸' => 'ذ', '𞺹' => 'ض', '𞺺' => 'ظ', '𞺻' => 'غ', '🄀' => '0.', '🄁' => '0,', '🄂' => '1,', '🄃' => '2,', '🄄' => '3,', '🄅' => '4,', '🄆' => '5,', '🄇' => '6,', '🄈' => '7,', '🄉' => '8,', '🄊' => '9,', '🄐' => '(A)', '🄑' => '(B)', '🄒' => '(C)', '🄓' => '(D)', '🄔' => '(E)', '🄕' => '(F)', '🄖' => '(G)', '🄗' => '(H)', '🄘' => '(I)', '🄙' => '(J)', '🄚' => '(K)', '🄛' => '(L)', '🄜' => '(M)', '🄝' => '(N)', '🄞' => '(O)', '🄟' => '(P)', '🄠' => '(Q)', '🄡' => '(R)', '🄢' => '(S)', '🄣' => '(T)', '🄤' => '(U)', '🄥' => '(V)', '🄦' => '(W)', '🄧' => '(X)', '🄨' => '(Y)', '🄩' => '(Z)', '🄪' => '〔S〕', '🄫' => 'C', '🄬' => 'R', '🄭' => 'CD', '🄮' => 'WZ', '🄰' => 'A', '🄱' => 'B', '🄲' => 'C', '🄳' => 'D', '🄴' => 'E', '🄵' => 'F', '🄶' => 'G', '🄷' => 'H', '🄸' => 'I', '🄹' => 'J', '🄺' => 'K', '🄻' => 'L', '🄼' => 'M', '🄽' => 'N', '🄾' => 'O', '🄿' => 'P', '🅀' => 'Q', '🅁' => 'R', '🅂' => 'S', '🅃' => 'T', '🅄' => 'U', '🅅' => 'V', '🅆' => 'W', '🅇' => 'X', '🅈' => 'Y', '🅉' => 'Z', '🅊' => 'HV', '🅋' => 'MV', '🅌' => 'SD', '🅍' => 'SS', '🅎' => 'PPV', '🅏' => 'WC', '🅪' => 'MC', '🅫' => 'MD', '🅬' => 'MR', '🆐' => 'DJ', '🈀' => 'ほか', '🈁' => 'ココ', '🈂' => 'サ', '🈐' => '手', '🈑' => '字', '🈒' => '双', '🈓' => 'デ', '🈔' => '二', '🈕' => '多', '🈖' => '解', '🈗' => '天', '🈘' => '交', '🈙' => '映', '🈚' => '無', '🈛' => '料', '🈜' => '前', '🈝' => '後', '🈞' => '再', '🈟' => '新', '🈠' => '初', '🈡' => '終', '🈢' => '生', '🈣' => '販', '🈤' => '声', '🈥' => '吹', '🈦' => '演', '🈧' => '投', '🈨' => '捕', '🈩' => '一', '🈪' => '三', '🈫' => '遊', '🈬' => '左', '🈭' => '中', '🈮' => '右', '🈯' => '指', '🈰' => '走', '🈱' => '打', '🈲' => '禁', '🈳' => '空', '🈴' => '合', '🈵' => '満', '🈶' => '有', '🈷' => '月', '🈸' => '申', '🈹' => '割', '🈺' => '営', '🈻' => '配', '🉀' => '〔本〕', '🉁' => '〔三〕', '🉂' => '〔二〕', '🉃' => '〔安〕', '🉄' => '〔点〕', '🉅' => '〔打〕', '🉆' => '〔盗〕', '🉇' => '〔勝〕', '🉈' => '〔敗〕', '🉐' => '得', '🉑' => '可', '🯰' => '0', '🯱' => '1', '🯲' => '2', '🯳' => '3', '🯴' => '4', '🯵' => '5', '🯶' => '6', '🯷' => '7', '🯸' => '8', '🯹' => '9'); diff --git a/vendor-bundle/symfony/polyfill-intl-normalizer/bootstrap.php b/vendor-bundle/symfony/polyfill-intl-normalizer/bootstrap.php new file mode 100644 index 000000000..ddf0b4363 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-intl-normalizer/bootstrap.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Phabel\Symfony\Polyfill\Intl\Normalizer as p; +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__ . '/bootstrap80.php'; +} +if (!\function_exists('normalizer_is_normalized')) { + function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) + { + return p\Normalizer::isNormalized($string, $form); + } +} +if (!\function_exists('normalizer_normalize')) { + function normalizer_normalize($string, $form = p\Normalizer::FORM_C) + { + return p\Normalizer::normalize($string, $form); + } +} diff --git a/vendor-bundle/symfony/polyfill-intl-normalizer/bootstrap80.php b/vendor-bundle/symfony/polyfill-intl-normalizer/bootstrap80.php new file mode 100644 index 000000000..82dc9cb8c --- /dev/null +++ b/vendor-bundle/symfony/polyfill-intl-normalizer/bootstrap80.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Phabel\Symfony\Polyfill\Intl\Normalizer as p; +if (!\function_exists('normalizer_is_normalized')) { + function normalizer_is_normalized($string, $form = p\Normalizer::FORM_C) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($form)) { + if (!\is_int($form)) { + if (!(\is_bool($form) || \is_numeric($form))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($form) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($form) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $form = (int) $form; + } + } + } + $phabelReturn = p\Normalizer::isNormalized((string) $string, (int) $form); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('normalizer_normalize')) { + function normalizer_normalize($string, $form = p\Normalizer::FORM_C) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($form)) { + if (!\is_int($form)) { + if (!(\is_bool($form) || \is_numeric($form))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($form) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($form) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $form = (int) $form; + } + } + } + $phabelReturn = p\Normalizer::normalize((string) $string, (int) $form); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/polyfill-mbstring/Mbstring.php b/vendor-bundle/symfony/polyfill-mbstring/Mbstring.php new file mode 100644 index 000000000..4e43d0da0 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-mbstring/Mbstring.php @@ -0,0 +1,695 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Polyfill\Mbstring; + +/** + * Partial mbstring implementation in PHP, iconv based, UTF-8 centric. + * + * Implemented: + * - mb_chr - Returns a specific character from its Unicode code point + * - mb_convert_encoding - Convert character encoding + * - mb_convert_variables - Convert character code in variable(s) + * - mb_decode_mimeheader - Decode string in MIME header field + * - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED + * - mb_decode_numericentity - Decode HTML numeric string reference to character + * - mb_encode_numericentity - Encode character to HTML numeric string reference + * - mb_convert_case - Perform case folding on a string + * - mb_detect_encoding - Detect character encoding + * - mb_get_info - Get internal settings of mbstring + * - mb_http_input - Detect HTTP input character encoding + * - mb_http_output - Set/Get HTTP output character encoding + * - mb_internal_encoding - Set/Get internal character encoding + * - mb_list_encodings - Returns an array of all supported encodings + * - mb_ord - Returns the Unicode code point of a character + * - mb_output_handler - Callback function converts character encoding in output buffer + * - mb_scrub - Replaces ill-formed byte sequences with substitute characters + * - mb_strlen - Get string length + * - mb_strpos - Find position of first occurrence of string in a string + * - mb_strrpos - Find position of last occurrence of a string in a string + * - mb_str_split - Convert a string to an array + * - mb_strtolower - Make a string lowercase + * - mb_strtoupper - Make a string uppercase + * - mb_substitute_character - Set/Get substitution character + * - mb_substr - Get part of string + * - mb_stripos - Finds position of first occurrence of a string within another, case insensitive + * - mb_stristr - Finds first occurrence of a string within another, case insensitive + * - mb_strrchr - Finds the last occurrence of a character in a string within another + * - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive + * - mb_strripos - Finds position of last occurrence of a string within another, case insensitive + * - mb_strstr - Finds first occurrence of a string within another + * - mb_strwidth - Return width of string + * - mb_substr_count - Count the number of substring occurrences + * + * Not implemented: + * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more) + * - mb_ereg_* - Regular expression with multibyte support + * - mb_parse_str - Parse GET/POST/COOKIE data and set global variable + * - mb_preferred_mime_name - Get MIME charset string + * - mb_regex_encoding - Returns current encoding for multibyte regex as string + * - mb_regex_set_options - Set/Get the default options for mbregex functions + * - mb_send_mail - Send encoded mail + * - mb_split - Split multibyte string using regular expression + * - mb_strcut - Get part of string + * - mb_strimwidth - Get truncated string with specified width + * + * @author Nicolas Grekas + * + * @internal + */ +final class Mbstring +{ + const MB_CASE_FOLD = \PHP_INT_MAX; + const CASE_FOLD = [['µ', 'ſ', "ͅ", 'ς', "ϐ", "ϑ", "ϕ", "ϖ", "ϰ", "ϱ", "ϵ", "ẛ", "ι"], ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "ṡ", 'ι']]; + private static $encodingList = ['ASCII', 'UTF-8']; + private static $language = 'neutral'; + private static $internalEncoding = 'UTF-8'; + public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) + { + if (\is_array($fromEncoding) || \false !== \strpos($fromEncoding, ',')) { + $fromEncoding = self::mb_detect_encoding($s, $fromEncoding); + } else { + $fromEncoding = self::getEncoding($fromEncoding); + } + $toEncoding = self::getEncoding($toEncoding); + if ('BASE64' === $fromEncoding) { + $s = \base64_decode($s); + $fromEncoding = $toEncoding; + } + if ('BASE64' === $toEncoding) { + return \base64_encode($s); + } + if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) { + if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) { + $fromEncoding = 'Windows-1252'; + } + if ('UTF-8' !== $fromEncoding) { + $s = \iconv($fromEncoding, 'UTF-8//IGNORE', $s); + } + return \preg_replace_callback('/[\\x80-\\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s); + } + if ('HTML-ENTITIES' === $fromEncoding) { + $s = \html_entity_decode($s, \ENT_COMPAT, 'UTF-8'); + $fromEncoding = 'UTF-8'; + } + return \iconv($fromEncoding, $toEncoding . '//IGNORE', $s); + } + public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars) + { + $ok = \true; + \array_walk_recursive($vars, function (&$v) use(&$ok, $toEncoding, $fromEncoding) { + if (\false === ($v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding))) { + $ok = \false; + } + }); + return $ok ? $fromEncoding : \false; + } + public static function mb_decode_mimeheader($s) + { + return \iconv_mime_decode($s, 2, self::$internalEncoding); + } + public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null) + { + \trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING); + } + public static function mb_decode_numericentity($s, $convmap, $encoding = null) + { + if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) { + \trigger_error('mb_decode_numericentity() expects parameter 1 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING); + return null; + } + if (!\is_array($convmap) || 80000 > \PHP_VERSION_ID && !$convmap) { + return \false; + } + if (null !== $encoding && !\is_scalar($encoding)) { + \trigger_error('mb_decode_numericentity() expects parameter 3 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING); + return ''; + // Instead of null (cf. mb_encode_numericentity). + } + $s = (string) $s; + if ('' === $s) { + return ''; + } + $encoding = self::getEncoding($encoding); + if ('UTF-8' === $encoding) { + $encoding = null; + if (!\preg_match('//u', $s)) { + $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); + } + } else { + $s = \iconv($encoding, 'UTF-8//IGNORE', $s); + } + $cnt = \floor(\count($convmap) / 4) * 4; + for ($i = 0; $i < $cnt; $i += 4) { + // collector_decode_htmlnumericentity ignores $convmap[$i + 3] + $convmap[$i] += $convmap[$i + 2]; + $convmap[$i + 1] += $convmap[$i + 2]; + } + $s = \preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use($cnt, $convmap) { + $c = isset($m[2]) ? (int) \hexdec($m[2]) : $m[1]; + for ($i = 0; $i < $cnt; $i += 4) { + if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) { + return self::mb_chr($c - $convmap[$i + 2]); + } + } + return $m[0]; + }, $s); + if (null === $encoding) { + return $s; + } + return \iconv('UTF-8', $encoding . '//IGNORE', $s); + } + public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = \false) + { + if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) { + \trigger_error('mb_encode_numericentity() expects parameter 1 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING); + return null; + } + if (!\is_array($convmap) || 80000 > \PHP_VERSION_ID && !$convmap) { + return \false; + } + if (null !== $encoding && !\is_scalar($encoding)) { + \trigger_error('mb_encode_numericentity() expects parameter 3 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING); + return null; + // Instead of '' (cf. mb_decode_numericentity). + } + if (null !== $is_hex && !\is_scalar($is_hex)) { + \trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, ' . \gettype($s) . ' given', \E_USER_WARNING); + return null; + } + $s = (string) $s; + if ('' === $s) { + return ''; + } + $encoding = self::getEncoding($encoding); + if ('UTF-8' === $encoding) { + $encoding = null; + if (!\preg_match('//u', $s)) { + $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); + } + } else { + $s = \iconv($encoding, 'UTF-8//IGNORE', $s); + } + static $ulenMask = ["\xc0" => 2, "\xd0" => 2, "\xe0" => 3, "\xf0" => 4]; + $cnt = \floor(\count($convmap) / 4) * 4; + $i = 0; + $len = \strlen($s); + $result = ''; + while ($i < $len) { + $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xf0"]; + $uchr = \substr($s, $i, $ulen); + $i += $ulen; + $c = self::mb_ord($uchr); + for ($j = 0; $j < $cnt; $j += 4) { + if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) { + $cOffset = $c + $convmap[$j + 2] & $convmap[$j + 3]; + $result .= $is_hex ? \sprintf('&#x%X;', $cOffset) : '&#' . $cOffset . ';'; + continue 2; + } + } + $result .= $uchr; + } + if (null === $encoding) { + return $result; + } + return \iconv('UTF-8', $encoding . '//IGNORE', $result); + } + public static function mb_convert_case($s, $mode, $encoding = null) + { + $s = (string) $s; + if ('' === $s) { + return ''; + } + $encoding = self::getEncoding($encoding); + if ('UTF-8' === $encoding) { + $encoding = null; + if (!\preg_match('//u', $s)) { + $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s); + } + } else { + $s = \iconv($encoding, 'UTF-8//IGNORE', $s); + } + if (\MB_CASE_TITLE == $mode) { + static $titleRegexp = null; + if (null === $titleRegexp) { + $titleRegexp = self::getData('titleCaseRegexp'); + } + $s = \preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s); + } else { + if (\MB_CASE_UPPER == $mode) { + static $upper = null; + if (null === $upper) { + $upper = self::getData('upperCase'); + } + $map = $upper; + } else { + if (self::MB_CASE_FOLD === $mode) { + $s = \str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); + } + static $lower = null; + if (null === $lower) { + $lower = self::getData('lowerCase'); + } + $map = $lower; + } + static $ulenMask = ["\xc0" => 2, "\xd0" => 2, "\xe0" => 3, "\xf0" => 4]; + $i = 0; + $len = \strlen($s); + while ($i < $len) { + $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xf0"]; + $uchr = \substr($s, $i, $ulen); + $i += $ulen; + if (isset($map[$uchr])) { + $uchr = $map[$uchr]; + $nlen = \strlen($uchr); + if ($nlen == $ulen) { + $nlen = $i; + do { + $s[--$nlen] = $uchr[--$ulen]; + } while ($ulen); + } else { + $s = \substr_replace($s, $uchr, $i - $ulen, $ulen); + $len += $nlen - $ulen; + $i += $nlen - $ulen; + } + } + } + } + if (null === $encoding) { + return $s; + } + return \iconv('UTF-8', $encoding . '//IGNORE', $s); + } + public static function mb_internal_encoding($encoding = null) + { + if (null === $encoding) { + return self::$internalEncoding; + } + $normalizedEncoding = self::getEncoding($encoding); + if ('UTF-8' === $normalizedEncoding || \false !== @\iconv($normalizedEncoding, $normalizedEncoding, ' ')) { + self::$internalEncoding = $normalizedEncoding; + return \true; + } + if (80000 > \PHP_VERSION_ID) { + return \false; + } + throw new \ValueError(\sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding)); + } + public static function mb_language($lang = null) + { + if (null === $lang) { + return self::$language; + } + switch ($normalizedLang = \strtolower($lang)) { + case 'uni': + case 'neutral': + self::$language = $normalizedLang; + return \true; + } + if (80000 > \PHP_VERSION_ID) { + return \false; + } + throw new \ValueError(\sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang)); + } + public static function mb_list_encodings() + { + return ['UTF-8']; + } + public static function mb_encoding_aliases($encoding) + { + switch (\strtoupper($encoding)) { + case 'UTF8': + case 'UTF-8': + return ['utf8']; + } + return \false; + } + public static function mb_check_encoding($var = null, $encoding = null) + { + if (null === $encoding) { + if (null === $var) { + return \false; + } + $encoding = self::$internalEncoding; + } + return self::mb_detect_encoding($var, [$encoding]) || \false !== @\iconv($encoding, $encoding, $var); + } + public static function mb_detect_encoding($str, $encodingList = null, $strict = \false) + { + if (null === $encodingList) { + $encodingList = self::$encodingList; + } else { + if (!\is_array($encodingList)) { + $encodingList = \array_map('trim', \explode(',', $encodingList)); + } + $encodingList = \array_map('strtoupper', $encodingList); + } + foreach ($encodingList as $enc) { + switch ($enc) { + case 'ASCII': + if (!\preg_match('/[\\x80-\\xFF]/', $str)) { + return $enc; + } + break; + case 'UTF8': + case 'UTF-8': + if (\preg_match('//u', $str)) { + return 'UTF-8'; + } + break; + default: + if (0 === \strncmp($enc, 'ISO-8859-', 9)) { + return $enc; + } + } + } + return \false; + } + public static function mb_detect_order($encodingList = null) + { + if (null === $encodingList) { + return self::$encodingList; + } + if (!\is_array($encodingList)) { + $encodingList = \array_map('trim', \explode(',', $encodingList)); + } + $encodingList = \array_map('strtoupper', $encodingList); + foreach ($encodingList as $enc) { + switch ($enc) { + default: + if (\strncmp($enc, 'ISO-8859-', 9)) { + return \false; + } + // no break + case 'ASCII': + case 'UTF8': + case 'UTF-8': + } + } + self::$encodingList = $encodingList; + return \true; + } + public static function mb_strlen($s, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return \strlen($s); + } + return @\iconv_strlen($s, $encoding); + } + public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return \strpos($haystack, $needle, $offset); + } + $needle = (string) $needle; + if ('' === $needle) { + if (80000 > \PHP_VERSION_ID) { + \trigger_error(__METHOD__ . ': Empty delimiter', \E_USER_WARNING); + return \false; + } + return 0; + } + return \iconv_strpos($haystack, $needle, $offset, $encoding); + } + public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return \strrpos($haystack, $needle, $offset); + } + if ($offset != (int) $offset) { + $offset = 0; + } elseif ($offset = (int) $offset) { + if ($offset < 0) { + if (0 > ($offset += self::mb_strlen($needle))) { + $haystack = self::mb_substr($haystack, 0, $offset, $encoding); + } + $offset = 0; + } else { + $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding); + } + } + $pos = '' !== $needle || 80000 > \PHP_VERSION_ID ? \iconv_strrpos($haystack, $needle, $encoding) : self::mb_strlen($haystack, $encoding); + return \false !== $pos ? $offset + $pos : \false; + } + public static function mb_str_split($string, $split_length = 1, $encoding = null) + { + if (null !== $string && !\is_scalar($string) && !(\is_object($string) && \method_exists($string, '__toString'))) { + \trigger_error('mb_str_split() expects parameter 1 to be string, ' . \gettype($string) . ' given', \E_USER_WARNING); + return null; + } + if (1 > ($split_length = (int) $split_length)) { + if (80000 > \PHP_VERSION_ID) { + \trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING); + return \false; + } + throw new \ValueError('Argument #2 ($length) must be greater than 0'); + } + if (null === $encoding) { + $encoding = \mb_internal_encoding(); + } + if ('UTF-8' === ($encoding = self::getEncoding($encoding))) { + $rx = '/('; + while (65535 < $split_length) { + $rx .= '.{65535}'; + $split_length -= 65535; + } + $rx .= '.{' . $split_length . '})/us'; + return \preg_split($rx, $string, null, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); + } + $result = []; + $length = \mb_strlen($string, $encoding); + for ($i = 0; $i < $length; $i += $split_length) { + $result[] = \mb_substr($string, $i, $split_length, $encoding); + } + return $result; + } + public static function mb_strtolower($s, $encoding = null) + { + return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding); + } + public static function mb_strtoupper($s, $encoding = null) + { + return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding); + } + public static function mb_substitute_character($c = null) + { + if (null === $c) { + return 'none'; + } + if (0 === \strcasecmp($c, 'none')) { + return \true; + } + if (80000 > \PHP_VERSION_ID) { + return \false; + } + throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint'); + } + public static function mb_substr($s, $start, $length = null, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return (string) \substr($s, $start, null === $length ? 2147483647 : $length); + } + if ($start < 0) { + $start = \iconv_strlen($s, $encoding) + $start; + if ($start < 0) { + $start = 0; + } + } + if (null === $length) { + $length = 2147483647; + } elseif ($length < 0) { + $length = \iconv_strlen($s, $encoding) + $length - $start; + if ($length < 0) { + return ''; + } + } + return (string) \iconv_substr($s, $start, $length, $encoding); + } + public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) + { + $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); + $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); + return self::mb_strpos($haystack, $needle, $offset, $encoding); + } + public static function mb_stristr($haystack, $needle, $part = \false, $encoding = null) + { + $pos = self::mb_stripos($haystack, $needle, 0, $encoding); + return self::getSubpart($pos, $part, $haystack, $encoding); + } + public static function mb_strrchr($haystack, $needle, $part = \false, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + $pos = \strrpos($haystack, $needle); + } else { + $needle = self::mb_substr($needle, 0, 1, $encoding); + $pos = \iconv_strrpos($haystack, $needle, $encoding); + } + return self::getSubpart($pos, $part, $haystack, $encoding); + } + public static function mb_strrichr($haystack, $needle, $part = \false, $encoding = null) + { + $needle = self::mb_substr($needle, 0, 1, $encoding); + $pos = self::mb_strripos($haystack, $needle, $encoding); + return self::getSubpart($pos, $part, $haystack, $encoding); + } + public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) + { + $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); + $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); + return self::mb_strrpos($haystack, $needle, $offset, $encoding); + } + public static function mb_strstr($haystack, $needle, $part = \false, $encoding = null) + { + $pos = \strpos($haystack, $needle); + if (\false === $pos) { + return \false; + } + if ($part) { + return \substr($haystack, 0, $pos); + } + return \substr($haystack, $pos); + } + public static function mb_get_info($type = 'all') + { + $info = ['internal_encoding' => self::$internalEncoding, 'http_output' => 'pass', 'http_output_conv_mimetypes' => '^(text/|application/xhtml\\+xml)', 'func_overload' => 0, 'func_overload_list' => 'no overload', 'mail_charset' => 'UTF-8', 'mail_header_encoding' => 'BASE64', 'mail_body_encoding' => 'BASE64', 'illegal_chars' => 0, 'encoding_translation' => 'Off', 'language' => self::$language, 'detect_order' => self::$encodingList, 'substitute_character' => 'none', 'strict_detection' => 'Off']; + if ('all' === $type) { + return $info; + } + if (isset($info[$type])) { + return $info[$type]; + } + return \false; + } + public static function mb_http_input($type = '') + { + return \false; + } + public static function mb_http_output($encoding = null) + { + return null !== $encoding ? 'pass' === $encoding : 'pass'; + } + public static function mb_strwidth($s, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('UTF-8' !== $encoding) { + $s = \iconv($encoding, 'UTF-8//IGNORE', $s); + } + $s = \preg_replace('/[\\x{1100}-\\x{115F}\\x{2329}\\x{232A}\\x{2E80}-\\x{303E}\\x{3040}-\\x{A4CF}\\x{AC00}-\\x{D7A3}\\x{F900}-\\x{FAFF}\\x{FE10}-\\x{FE19}\\x{FE30}-\\x{FE6F}\\x{FF00}-\\x{FF60}\\x{FFE0}-\\x{FFE6}\\x{20000}-\\x{2FFFD}\\x{30000}-\\x{3FFFD}]/u', '', $s, -1, $wide); + return ($wide << 1) + \iconv_strlen($s, 'UTF-8'); + } + public static function mb_substr_count($haystack, $needle, $encoding = null) + { + return \substr_count($haystack, $needle); + } + public static function mb_output_handler($contents, $status) + { + return $contents; + } + public static function mb_chr($code, $encoding = null) + { + if (0x80 > ($code %= 0x200000)) { + $s = \chr($code); + } elseif (0x800 > $code) { + $s = \chr(0xc0 | $code >> 6) . \chr(0x80 | $code & 0x3f); + } elseif (0x10000 > $code) { + $s = \chr(0xe0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f); + } else { + $s = \chr(0xf0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3f) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f); + } + if ('UTF-8' !== ($encoding = self::getEncoding($encoding))) { + $s = \mb_convert_encoding($s, $encoding, 'UTF-8'); + } + return $s; + } + public static function mb_ord($s, $encoding = null) + { + if ('UTF-8' !== ($encoding = self::getEncoding($encoding))) { + $s = \mb_convert_encoding($s, 'UTF-8', $encoding); + } + if (1 === \strlen($s)) { + return \ord($s); + } + $code = ($s = \unpack('C*', \substr($s, 0, 4))) ? $s[1] : 0; + if (0xf0 <= $code) { + return ($code - 0xf0 << 18) + ($s[2] - 0x80 << 12) + ($s[3] - 0x80 << 6) + $s[4] - 0x80; + } + if (0xe0 <= $code) { + return ($code - 0xe0 << 12) + ($s[2] - 0x80 << 6) + $s[3] - 0x80; + } + if (0xc0 <= $code) { + return ($code - 0xc0 << 6) + $s[2] - 0x80; + } + return $code; + } + private static function getSubpart($pos, $part, $haystack, $encoding) + { + if (\false === $pos) { + return \false; + } + if ($part) { + return self::mb_substr($haystack, 0, $pos, $encoding); + } + return self::mb_substr($haystack, $pos, null, $encoding); + } + private static function html_encoding_callback(array $m) + { + $i = 1; + $entities = ''; + $m = \unpack('C*', \htmlentities($m[0], \ENT_COMPAT, 'UTF-8')); + while (isset($m[$i])) { + if (0x80 > $m[$i]) { + $entities .= \chr($m[$i++]); + continue; + } + if (0xf0 <= $m[$i]) { + $c = ($m[$i++] - 0xf0 << 18) + ($m[$i++] - 0x80 << 12) + ($m[$i++] - 0x80 << 6) + $m[$i++] - 0x80; + } elseif (0xe0 <= $m[$i]) { + $c = ($m[$i++] - 0xe0 << 12) + ($m[$i++] - 0x80 << 6) + $m[$i++] - 0x80; + } else { + $c = ($m[$i++] - 0xc0 << 6) + $m[$i++] - 0x80; + } + $entities .= '&#' . $c . ';'; + } + return $entities; + } + private static function title_case(array $s) + { + return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8') . self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8'); + } + private static function getData($file) + { + if (\file_exists($file = __DIR__ . '/Resources/unidata/' . $file . '.php')) { + return require $file; + } + return \false; + } + private static function getEncoding($encoding) + { + if (null === $encoding) { + return self::$internalEncoding; + } + if ('UTF-8' === $encoding) { + return 'UTF-8'; + } + $encoding = \strtoupper($encoding); + if ('8BIT' === $encoding || 'BINARY' === $encoding) { + return 'CP850'; + } + if ('UTF8' === $encoding) { + return 'UTF-8'; + } + return $encoding; + } +} diff --git a/vendor-bundle/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php b/vendor-bundle/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php new file mode 100644 index 000000000..954bfa9ec --- /dev/null +++ b/vendor-bundle/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php @@ -0,0 +1,5 @@ + 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd', 'E' => 'e', 'F' => 'f', 'G' => 'g', 'H' => 'h', 'I' => 'i', 'J' => 'j', 'K' => 'k', 'L' => 'l', 'M' => 'm', 'N' => 'n', 'O' => 'o', 'P' => 'p', 'Q' => 'q', 'R' => 'r', 'S' => 's', 'T' => 't', 'U' => 'u', 'V' => 'v', 'W' => 'w', 'X' => 'x', 'Y' => 'y', 'Z' => 'z', 'À' => 'à', 'Á' => 'á', 'Â' => 'â', 'Ã' => 'ã', 'Ä' => 'ä', 'Å' => 'å', 'Æ' => 'æ', 'Ç' => 'ç', 'È' => 'è', 'É' => 'é', 'Ê' => 'ê', 'Ë' => 'ë', 'Ì' => 'ì', 'Í' => 'í', 'Î' => 'î', 'Ï' => 'ï', 'Ð' => 'ð', 'Ñ' => 'ñ', 'Ò' => 'ò', 'Ó' => 'ó', 'Ô' => 'ô', 'Õ' => 'õ', 'Ö' => 'ö', 'Ø' => 'ø', 'Ù' => 'ù', 'Ú' => 'ú', 'Û' => 'û', 'Ü' => 'ü', 'Ý' => 'ý', 'Þ' => 'þ', 'Ā' => 'ā', 'Ă' => 'ă', 'Ą' => 'ą', 'Ć' => 'ć', 'Ĉ' => 'ĉ', 'Ċ' => 'ċ', 'Č' => 'č', 'Ď' => 'ď', 'Đ' => 'đ', 'Ē' => 'ē', 'Ĕ' => 'ĕ', 'Ė' => 'ė', 'Ę' => 'ę', 'Ě' => 'ě', 'Ĝ' => 'ĝ', 'Ğ' => 'ğ', 'Ġ' => 'ġ', 'Ģ' => 'ģ', 'Ĥ' => 'ĥ', 'Ħ' => 'ħ', 'Ĩ' => 'ĩ', 'Ī' => 'ī', 'Ĭ' => 'ĭ', 'Į' => 'į', 'İ' => 'i̇', 'IJ' => 'ij', 'Ĵ' => 'ĵ', 'Ķ' => 'ķ', 'Ĺ' => 'ĺ', 'Ļ' => 'ļ', 'Ľ' => 'ľ', 'Ŀ' => 'ŀ', 'Ł' => 'ł', 'Ń' => 'ń', 'Ņ' => 'ņ', 'Ň' => 'ň', 'Ŋ' => 'ŋ', 'Ō' => 'ō', 'Ŏ' => 'ŏ', 'Ő' => 'ő', 'Œ' => 'œ', 'Ŕ' => 'ŕ', 'Ŗ' => 'ŗ', 'Ř' => 'ř', 'Ś' => 'ś', 'Ŝ' => 'ŝ', 'Ş' => 'ş', 'Š' => 'š', 'Ţ' => 'ţ', 'Ť' => 'ť', 'Ŧ' => 'ŧ', 'Ũ' => 'ũ', 'Ū' => 'ū', 'Ŭ' => 'ŭ', 'Ů' => 'ů', 'Ű' => 'ű', 'Ų' => 'ų', 'Ŵ' => 'ŵ', 'Ŷ' => 'ŷ', 'Ÿ' => 'ÿ', 'Ź' => 'ź', 'Ż' => 'ż', 'Ž' => 'ž', 'Ɓ' => 'ɓ', 'Ƃ' => 'ƃ', 'Ƅ' => 'ƅ', 'Ɔ' => 'ɔ', 'Ƈ' => 'ƈ', 'Ɖ' => 'ɖ', 'Ɗ' => 'ɗ', 'Ƌ' => 'ƌ', 'Ǝ' => 'ǝ', 'Ə' => 'ə', 'Ɛ' => 'ɛ', 'Ƒ' => 'ƒ', 'Ɠ' => 'ɠ', 'Ɣ' => 'ɣ', 'Ɩ' => 'ɩ', 'Ɨ' => 'ɨ', 'Ƙ' => 'ƙ', 'Ɯ' => 'ɯ', 'Ɲ' => 'ɲ', 'Ɵ' => 'ɵ', 'Ơ' => 'ơ', 'Ƣ' => 'ƣ', 'Ƥ' => 'ƥ', 'Ʀ' => 'ʀ', 'Ƨ' => 'ƨ', 'Ʃ' => 'ʃ', 'Ƭ' => 'ƭ', 'Ʈ' => 'ʈ', 'Ư' => 'ư', 'Ʊ' => 'ʊ', 'Ʋ' => 'ʋ', 'Ƴ' => 'ƴ', 'Ƶ' => 'ƶ', 'Ʒ' => 'ʒ', 'Ƹ' => 'ƹ', 'Ƽ' => 'ƽ', 'DŽ' => 'dž', 'Dž' => 'dž', 'LJ' => 'lj', 'Lj' => 'lj', 'NJ' => 'nj', 'Nj' => 'nj', 'Ǎ' => 'ǎ', 'Ǐ' => 'ǐ', 'Ǒ' => 'ǒ', 'Ǔ' => 'ǔ', 'Ǖ' => 'ǖ', 'Ǘ' => 'ǘ', 'Ǚ' => 'ǚ', 'Ǜ' => 'ǜ', 'Ǟ' => 'ǟ', 'Ǡ' => 'ǡ', 'Ǣ' => 'ǣ', 'Ǥ' => 'ǥ', 'Ǧ' => 'ǧ', 'Ǩ' => 'ǩ', 'Ǫ' => 'ǫ', 'Ǭ' => 'ǭ', 'Ǯ' => 'ǯ', 'DZ' => 'dz', 'Dz' => 'dz', 'Ǵ' => 'ǵ', 'Ƕ' => 'ƕ', 'Ƿ' => 'ƿ', 'Ǹ' => 'ǹ', 'Ǻ' => 'ǻ', 'Ǽ' => 'ǽ', 'Ǿ' => 'ǿ', 'Ȁ' => 'ȁ', 'Ȃ' => 'ȃ', 'Ȅ' => 'ȅ', 'Ȇ' => 'ȇ', 'Ȉ' => 'ȉ', 'Ȋ' => 'ȋ', 'Ȍ' => 'ȍ', 'Ȏ' => 'ȏ', 'Ȑ' => 'ȑ', 'Ȓ' => 'ȓ', 'Ȕ' => 'ȕ', 'Ȗ' => 'ȗ', 'Ș' => 'ș', 'Ț' => 'ț', 'Ȝ' => 'ȝ', 'Ȟ' => 'ȟ', 'Ƞ' => 'ƞ', 'Ȣ' => 'ȣ', 'Ȥ' => 'ȥ', 'Ȧ' => 'ȧ', 'Ȩ' => 'ȩ', 'Ȫ' => 'ȫ', 'Ȭ' => 'ȭ', 'Ȯ' => 'ȯ', 'Ȱ' => 'ȱ', 'Ȳ' => 'ȳ', 'Ⱥ' => 'ⱥ', 'Ȼ' => 'ȼ', 'Ƚ' => 'ƚ', 'Ⱦ' => 'ⱦ', 'Ɂ' => 'ɂ', 'Ƀ' => 'ƀ', 'Ʉ' => 'ʉ', 'Ʌ' => 'ʌ', 'Ɇ' => 'ɇ', 'Ɉ' => 'ɉ', 'Ɋ' => 'ɋ', 'Ɍ' => 'ɍ', 'Ɏ' => 'ɏ', 'Ͱ' => 'ͱ', 'Ͳ' => 'ͳ', 'Ͷ' => 'ͷ', 'Ϳ' => 'ϳ', 'Ά' => 'ά', 'Έ' => 'έ', 'Ή' => 'ή', 'Ί' => 'ί', 'Ό' => 'ό', 'Ύ' => 'ύ', 'Ώ' => 'ώ', 'Α' => 'α', 'Β' => 'β', 'Γ' => 'γ', 'Δ' => 'δ', 'Ε' => 'ε', 'Ζ' => 'ζ', 'Η' => 'η', 'Θ' => 'θ', 'Ι' => 'ι', 'Κ' => 'κ', 'Λ' => 'λ', 'Μ' => 'μ', 'Ν' => 'ν', 'Ξ' => 'ξ', 'Ο' => 'ο', 'Π' => 'π', 'Ρ' => 'ρ', 'Σ' => 'σ', 'Τ' => 'τ', 'Υ' => 'υ', 'Φ' => 'φ', 'Χ' => 'χ', 'Ψ' => 'ψ', 'Ω' => 'ω', 'Ϊ' => 'ϊ', 'Ϋ' => 'ϋ', 'Ϗ' => 'ϗ', 'Ϙ' => 'ϙ', 'Ϛ' => 'ϛ', 'Ϝ' => 'ϝ', 'Ϟ' => 'ϟ', 'Ϡ' => 'ϡ', 'Ϣ' => 'ϣ', 'Ϥ' => 'ϥ', 'Ϧ' => 'ϧ', 'Ϩ' => 'ϩ', 'Ϫ' => 'ϫ', 'Ϭ' => 'ϭ', 'Ϯ' => 'ϯ', 'ϴ' => 'θ', 'Ϸ' => 'ϸ', 'Ϲ' => 'ϲ', 'Ϻ' => 'ϻ', 'Ͻ' => 'ͻ', 'Ͼ' => 'ͼ', 'Ͽ' => 'ͽ', 'Ѐ' => 'ѐ', 'Ё' => 'ё', 'Ђ' => 'ђ', 'Ѓ' => 'ѓ', 'Є' => 'є', 'Ѕ' => 'ѕ', 'І' => 'і', 'Ї' => 'ї', 'Ј' => 'ј', 'Љ' => 'љ', 'Њ' => 'њ', 'Ћ' => 'ћ', 'Ќ' => 'ќ', 'Ѝ' => 'ѝ', 'Ў' => 'ў', 'Џ' => 'џ', 'А' => 'а', 'Б' => 'б', 'В' => 'в', 'Г' => 'г', 'Д' => 'д', 'Е' => 'е', 'Ж' => 'ж', 'З' => 'з', 'И' => 'и', 'Й' => 'й', 'К' => 'к', 'Л' => 'л', 'М' => 'м', 'Н' => 'н', 'О' => 'о', 'П' => 'п', 'Р' => 'р', 'С' => 'с', 'Т' => 'т', 'У' => 'у', 'Ф' => 'ф', 'Х' => 'х', 'Ц' => 'ц', 'Ч' => 'ч', 'Ш' => 'ш', 'Щ' => 'щ', 'Ъ' => 'ъ', 'Ы' => 'ы', 'Ь' => 'ь', 'Э' => 'э', 'Ю' => 'ю', 'Я' => 'я', 'Ѡ' => 'ѡ', 'Ѣ' => 'ѣ', 'Ѥ' => 'ѥ', 'Ѧ' => 'ѧ', 'Ѩ' => 'ѩ', 'Ѫ' => 'ѫ', 'Ѭ' => 'ѭ', 'Ѯ' => 'ѯ', 'Ѱ' => 'ѱ', 'Ѳ' => 'ѳ', 'Ѵ' => 'ѵ', 'Ѷ' => 'ѷ', 'Ѹ' => 'ѹ', 'Ѻ' => 'ѻ', 'Ѽ' => 'ѽ', 'Ѿ' => 'ѿ', 'Ҁ' => 'ҁ', 'Ҋ' => 'ҋ', 'Ҍ' => 'ҍ', 'Ҏ' => 'ҏ', 'Ґ' => 'ґ', 'Ғ' => 'ғ', 'Ҕ' => 'ҕ', 'Җ' => 'җ', 'Ҙ' => 'ҙ', 'Қ' => 'қ', 'Ҝ' => 'ҝ', 'Ҟ' => 'ҟ', 'Ҡ' => 'ҡ', 'Ң' => 'ң', 'Ҥ' => 'ҥ', 'Ҧ' => 'ҧ', 'Ҩ' => 'ҩ', 'Ҫ' => 'ҫ', 'Ҭ' => 'ҭ', 'Ү' => 'ү', 'Ұ' => 'ұ', 'Ҳ' => 'ҳ', 'Ҵ' => 'ҵ', 'Ҷ' => 'ҷ', 'Ҹ' => 'ҹ', 'Һ' => 'һ', 'Ҽ' => 'ҽ', 'Ҿ' => 'ҿ', 'Ӏ' => 'ӏ', 'Ӂ' => 'ӂ', 'Ӄ' => 'ӄ', 'Ӆ' => 'ӆ', 'Ӈ' => 'ӈ', 'Ӊ' => 'ӊ', 'Ӌ' => 'ӌ', 'Ӎ' => 'ӎ', 'Ӑ' => 'ӑ', 'Ӓ' => 'ӓ', 'Ӕ' => 'ӕ', 'Ӗ' => 'ӗ', 'Ә' => 'ә', 'Ӛ' => 'ӛ', 'Ӝ' => 'ӝ', 'Ӟ' => 'ӟ', 'Ӡ' => 'ӡ', 'Ӣ' => 'ӣ', 'Ӥ' => 'ӥ', 'Ӧ' => 'ӧ', 'Ө' => 'ө', 'Ӫ' => 'ӫ', 'Ӭ' => 'ӭ', 'Ӯ' => 'ӯ', 'Ӱ' => 'ӱ', 'Ӳ' => 'ӳ', 'Ӵ' => 'ӵ', 'Ӷ' => 'ӷ', 'Ӹ' => 'ӹ', 'Ӻ' => 'ӻ', 'Ӽ' => 'ӽ', 'Ӿ' => 'ӿ', 'Ԁ' => 'ԁ', 'Ԃ' => 'ԃ', 'Ԅ' => 'ԅ', 'Ԇ' => 'ԇ', 'Ԉ' => 'ԉ', 'Ԋ' => 'ԋ', 'Ԍ' => 'ԍ', 'Ԏ' => 'ԏ', 'Ԑ' => 'ԑ', 'Ԓ' => 'ԓ', 'Ԕ' => 'ԕ', 'Ԗ' => 'ԗ', 'Ԙ' => 'ԙ', 'Ԛ' => 'ԛ', 'Ԝ' => 'ԝ', 'Ԟ' => 'ԟ', 'Ԡ' => 'ԡ', 'Ԣ' => 'ԣ', 'Ԥ' => 'ԥ', 'Ԧ' => 'ԧ', 'Ԩ' => 'ԩ', 'Ԫ' => 'ԫ', 'Ԭ' => 'ԭ', 'Ԯ' => 'ԯ', 'Ա' => 'ա', 'Բ' => 'բ', 'Գ' => 'գ', 'Դ' => 'դ', 'Ե' => 'ե', 'Զ' => 'զ', 'Է' => 'է', 'Ը' => 'ը', 'Թ' => 'թ', 'Ժ' => 'ժ', 'Ի' => 'ի', 'Լ' => 'լ', 'Խ' => 'խ', 'Ծ' => 'ծ', 'Կ' => 'կ', 'Հ' => 'հ', 'Ձ' => 'ձ', 'Ղ' => 'ղ', 'Ճ' => 'ճ', 'Մ' => 'մ', 'Յ' => 'յ', 'Ն' => 'ն', 'Շ' => 'շ', 'Ո' => 'ո', 'Չ' => 'չ', 'Պ' => 'պ', 'Ջ' => 'ջ', 'Ռ' => 'ռ', 'Ս' => 'ս', 'Վ' => 'վ', 'Տ' => 'տ', 'Ր' => 'ր', 'Ց' => 'ց', 'Ւ' => 'ւ', 'Փ' => 'փ', 'Ք' => 'ք', 'Օ' => 'օ', 'Ֆ' => 'ֆ', 'Ⴀ' => 'ⴀ', 'Ⴁ' => 'ⴁ', 'Ⴂ' => 'ⴂ', 'Ⴃ' => 'ⴃ', 'Ⴄ' => 'ⴄ', 'Ⴅ' => 'ⴅ', 'Ⴆ' => 'ⴆ', 'Ⴇ' => 'ⴇ', 'Ⴈ' => 'ⴈ', 'Ⴉ' => 'ⴉ', 'Ⴊ' => 'ⴊ', 'Ⴋ' => 'ⴋ', 'Ⴌ' => 'ⴌ', 'Ⴍ' => 'ⴍ', 'Ⴎ' => 'ⴎ', 'Ⴏ' => 'ⴏ', 'Ⴐ' => 'ⴐ', 'Ⴑ' => 'ⴑ', 'Ⴒ' => 'ⴒ', 'Ⴓ' => 'ⴓ', 'Ⴔ' => 'ⴔ', 'Ⴕ' => 'ⴕ', 'Ⴖ' => 'ⴖ', 'Ⴗ' => 'ⴗ', 'Ⴘ' => 'ⴘ', 'Ⴙ' => 'ⴙ', 'Ⴚ' => 'ⴚ', 'Ⴛ' => 'ⴛ', 'Ⴜ' => 'ⴜ', 'Ⴝ' => 'ⴝ', 'Ⴞ' => 'ⴞ', 'Ⴟ' => 'ⴟ', 'Ⴠ' => 'ⴠ', 'Ⴡ' => 'ⴡ', 'Ⴢ' => 'ⴢ', 'Ⴣ' => 'ⴣ', 'Ⴤ' => 'ⴤ', 'Ⴥ' => 'ⴥ', 'Ⴧ' => 'ⴧ', 'Ⴭ' => 'ⴭ', 'Ꭰ' => 'ꭰ', 'Ꭱ' => 'ꭱ', 'Ꭲ' => 'ꭲ', 'Ꭳ' => 'ꭳ', 'Ꭴ' => 'ꭴ', 'Ꭵ' => 'ꭵ', 'Ꭶ' => 'ꭶ', 'Ꭷ' => 'ꭷ', 'Ꭸ' => 'ꭸ', 'Ꭹ' => 'ꭹ', 'Ꭺ' => 'ꭺ', 'Ꭻ' => 'ꭻ', 'Ꭼ' => 'ꭼ', 'Ꭽ' => 'ꭽ', 'Ꭾ' => 'ꭾ', 'Ꭿ' => 'ꭿ', 'Ꮀ' => 'ꮀ', 'Ꮁ' => 'ꮁ', 'Ꮂ' => 'ꮂ', 'Ꮃ' => 'ꮃ', 'Ꮄ' => 'ꮄ', 'Ꮅ' => 'ꮅ', 'Ꮆ' => 'ꮆ', 'Ꮇ' => 'ꮇ', 'Ꮈ' => 'ꮈ', 'Ꮉ' => 'ꮉ', 'Ꮊ' => 'ꮊ', 'Ꮋ' => 'ꮋ', 'Ꮌ' => 'ꮌ', 'Ꮍ' => 'ꮍ', 'Ꮎ' => 'ꮎ', 'Ꮏ' => 'ꮏ', 'Ꮐ' => 'ꮐ', 'Ꮑ' => 'ꮑ', 'Ꮒ' => 'ꮒ', 'Ꮓ' => 'ꮓ', 'Ꮔ' => 'ꮔ', 'Ꮕ' => 'ꮕ', 'Ꮖ' => 'ꮖ', 'Ꮗ' => 'ꮗ', 'Ꮘ' => 'ꮘ', 'Ꮙ' => 'ꮙ', 'Ꮚ' => 'ꮚ', 'Ꮛ' => 'ꮛ', 'Ꮜ' => 'ꮜ', 'Ꮝ' => 'ꮝ', 'Ꮞ' => 'ꮞ', 'Ꮟ' => 'ꮟ', 'Ꮠ' => 'ꮠ', 'Ꮡ' => 'ꮡ', 'Ꮢ' => 'ꮢ', 'Ꮣ' => 'ꮣ', 'Ꮤ' => 'ꮤ', 'Ꮥ' => 'ꮥ', 'Ꮦ' => 'ꮦ', 'Ꮧ' => 'ꮧ', 'Ꮨ' => 'ꮨ', 'Ꮩ' => 'ꮩ', 'Ꮪ' => 'ꮪ', 'Ꮫ' => 'ꮫ', 'Ꮬ' => 'ꮬ', 'Ꮭ' => 'ꮭ', 'Ꮮ' => 'ꮮ', 'Ꮯ' => 'ꮯ', 'Ꮰ' => 'ꮰ', 'Ꮱ' => 'ꮱ', 'Ꮲ' => 'ꮲ', 'Ꮳ' => 'ꮳ', 'Ꮴ' => 'ꮴ', 'Ꮵ' => 'ꮵ', 'Ꮶ' => 'ꮶ', 'Ꮷ' => 'ꮷ', 'Ꮸ' => 'ꮸ', 'Ꮹ' => 'ꮹ', 'Ꮺ' => 'ꮺ', 'Ꮻ' => 'ꮻ', 'Ꮼ' => 'ꮼ', 'Ꮽ' => 'ꮽ', 'Ꮾ' => 'ꮾ', 'Ꮿ' => 'ꮿ', 'Ᏸ' => 'ᏸ', 'Ᏹ' => 'ᏹ', 'Ᏺ' => 'ᏺ', 'Ᏻ' => 'ᏻ', 'Ᏼ' => 'ᏼ', 'Ᏽ' => 'ᏽ', 'Ა' => 'ა', 'Ბ' => 'ბ', 'Გ' => 'გ', 'Დ' => 'დ', 'Ე' => 'ე', 'Ვ' => 'ვ', 'Ზ' => 'ზ', 'Თ' => 'თ', 'Ი' => 'ი', 'Კ' => 'კ', 'Ლ' => 'ლ', 'Მ' => 'მ', 'Ნ' => 'ნ', 'Ო' => 'ო', 'Პ' => 'პ', 'Ჟ' => 'ჟ', 'Რ' => 'რ', 'Ს' => 'ს', 'Ტ' => 'ტ', 'Უ' => 'უ', 'Ფ' => 'ფ', 'Ქ' => 'ქ', 'Ღ' => 'ღ', 'Ყ' => 'ყ', 'Შ' => 'შ', 'Ჩ' => 'ჩ', 'Ც' => 'ც', 'Ძ' => 'ძ', 'Წ' => 'წ', 'Ჭ' => 'ჭ', 'Ხ' => 'ხ', 'Ჯ' => 'ჯ', 'Ჰ' => 'ჰ', 'Ჱ' => 'ჱ', 'Ჲ' => 'ჲ', 'Ჳ' => 'ჳ', 'Ჴ' => 'ჴ', 'Ჵ' => 'ჵ', 'Ჶ' => 'ჶ', 'Ჷ' => 'ჷ', 'Ჸ' => 'ჸ', 'Ჹ' => 'ჹ', 'Ჺ' => 'ჺ', 'Ჽ' => 'ჽ', 'Ჾ' => 'ჾ', 'Ჿ' => 'ჿ', 'Ḁ' => 'ḁ', 'Ḃ' => 'ḃ', 'Ḅ' => 'ḅ', 'Ḇ' => 'ḇ', 'Ḉ' => 'ḉ', 'Ḋ' => 'ḋ', 'Ḍ' => 'ḍ', 'Ḏ' => 'ḏ', 'Ḑ' => 'ḑ', 'Ḓ' => 'ḓ', 'Ḕ' => 'ḕ', 'Ḗ' => 'ḗ', 'Ḙ' => 'ḙ', 'Ḛ' => 'ḛ', 'Ḝ' => 'ḝ', 'Ḟ' => 'ḟ', 'Ḡ' => 'ḡ', 'Ḣ' => 'ḣ', 'Ḥ' => 'ḥ', 'Ḧ' => 'ḧ', 'Ḩ' => 'ḩ', 'Ḫ' => 'ḫ', 'Ḭ' => 'ḭ', 'Ḯ' => 'ḯ', 'Ḱ' => 'ḱ', 'Ḳ' => 'ḳ', 'Ḵ' => 'ḵ', 'Ḷ' => 'ḷ', 'Ḹ' => 'ḹ', 'Ḻ' => 'ḻ', 'Ḽ' => 'ḽ', 'Ḿ' => 'ḿ', 'Ṁ' => 'ṁ', 'Ṃ' => 'ṃ', 'Ṅ' => 'ṅ', 'Ṇ' => 'ṇ', 'Ṉ' => 'ṉ', 'Ṋ' => 'ṋ', 'Ṍ' => 'ṍ', 'Ṏ' => 'ṏ', 'Ṑ' => 'ṑ', 'Ṓ' => 'ṓ', 'Ṕ' => 'ṕ', 'Ṗ' => 'ṗ', 'Ṙ' => 'ṙ', 'Ṛ' => 'ṛ', 'Ṝ' => 'ṝ', 'Ṟ' => 'ṟ', 'Ṡ' => 'ṡ', 'Ṣ' => 'ṣ', 'Ṥ' => 'ṥ', 'Ṧ' => 'ṧ', 'Ṩ' => 'ṩ', 'Ṫ' => 'ṫ', 'Ṭ' => 'ṭ', 'Ṯ' => 'ṯ', 'Ṱ' => 'ṱ', 'Ṳ' => 'ṳ', 'Ṵ' => 'ṵ', 'Ṷ' => 'ṷ', 'Ṹ' => 'ṹ', 'Ṻ' => 'ṻ', 'Ṽ' => 'ṽ', 'Ṿ' => 'ṿ', 'Ẁ' => 'ẁ', 'Ẃ' => 'ẃ', 'Ẅ' => 'ẅ', 'Ẇ' => 'ẇ', 'Ẉ' => 'ẉ', 'Ẋ' => 'ẋ', 'Ẍ' => 'ẍ', 'Ẏ' => 'ẏ', 'Ẑ' => 'ẑ', 'Ẓ' => 'ẓ', 'Ẕ' => 'ẕ', 'ẞ' => 'ß', 'Ạ' => 'ạ', 'Ả' => 'ả', 'Ấ' => 'ấ', 'Ầ' => 'ầ', 'Ẩ' => 'ẩ', 'Ẫ' => 'ẫ', 'Ậ' => 'ậ', 'Ắ' => 'ắ', 'Ằ' => 'ằ', 'Ẳ' => 'ẳ', 'Ẵ' => 'ẵ', 'Ặ' => 'ặ', 'Ẹ' => 'ẹ', 'Ẻ' => 'ẻ', 'Ẽ' => 'ẽ', 'Ế' => 'ế', 'Ề' => 'ề', 'Ể' => 'ể', 'Ễ' => 'ễ', 'Ệ' => 'ệ', 'Ỉ' => 'ỉ', 'Ị' => 'ị', 'Ọ' => 'ọ', 'Ỏ' => 'ỏ', 'Ố' => 'ố', 'Ồ' => 'ồ', 'Ổ' => 'ổ', 'Ỗ' => 'ỗ', 'Ộ' => 'ộ', 'Ớ' => 'ớ', 'Ờ' => 'ờ', 'Ở' => 'ở', 'Ỡ' => 'ỡ', 'Ợ' => 'ợ', 'Ụ' => 'ụ', 'Ủ' => 'ủ', 'Ứ' => 'ứ', 'Ừ' => 'ừ', 'Ử' => 'ử', 'Ữ' => 'ữ', 'Ự' => 'ự', 'Ỳ' => 'ỳ', 'Ỵ' => 'ỵ', 'Ỷ' => 'ỷ', 'Ỹ' => 'ỹ', 'Ỻ' => 'ỻ', 'Ỽ' => 'ỽ', 'Ỿ' => 'ỿ', 'Ἀ' => 'ἀ', 'Ἁ' => 'ἁ', 'Ἂ' => 'ἂ', 'Ἃ' => 'ἃ', 'Ἄ' => 'ἄ', 'Ἅ' => 'ἅ', 'Ἆ' => 'ἆ', 'Ἇ' => 'ἇ', 'Ἐ' => 'ἐ', 'Ἑ' => 'ἑ', 'Ἒ' => 'ἒ', 'Ἓ' => 'ἓ', 'Ἔ' => 'ἔ', 'Ἕ' => 'ἕ', 'Ἠ' => 'ἠ', 'Ἡ' => 'ἡ', 'Ἢ' => 'ἢ', 'Ἣ' => 'ἣ', 'Ἤ' => 'ἤ', 'Ἥ' => 'ἥ', 'Ἦ' => 'ἦ', 'Ἧ' => 'ἧ', 'Ἰ' => 'ἰ', 'Ἱ' => 'ἱ', 'Ἲ' => 'ἲ', 'Ἳ' => 'ἳ', 'Ἴ' => 'ἴ', 'Ἵ' => 'ἵ', 'Ἶ' => 'ἶ', 'Ἷ' => 'ἷ', 'Ὀ' => 'ὀ', 'Ὁ' => 'ὁ', 'Ὂ' => 'ὂ', 'Ὃ' => 'ὃ', 'Ὄ' => 'ὄ', 'Ὅ' => 'ὅ', 'Ὑ' => 'ὑ', 'Ὓ' => 'ὓ', 'Ὕ' => 'ὕ', 'Ὗ' => 'ὗ', 'Ὠ' => 'ὠ', 'Ὡ' => 'ὡ', 'Ὢ' => 'ὢ', 'Ὣ' => 'ὣ', 'Ὤ' => 'ὤ', 'Ὥ' => 'ὥ', 'Ὦ' => 'ὦ', 'Ὧ' => 'ὧ', 'ᾈ' => 'ᾀ', 'ᾉ' => 'ᾁ', 'ᾊ' => 'ᾂ', 'ᾋ' => 'ᾃ', 'ᾌ' => 'ᾄ', 'ᾍ' => 'ᾅ', 'ᾎ' => 'ᾆ', 'ᾏ' => 'ᾇ', 'ᾘ' => 'ᾐ', 'ᾙ' => 'ᾑ', 'ᾚ' => 'ᾒ', 'ᾛ' => 'ᾓ', 'ᾜ' => 'ᾔ', 'ᾝ' => 'ᾕ', 'ᾞ' => 'ᾖ', 'ᾟ' => 'ᾗ', 'ᾨ' => 'ᾠ', 'ᾩ' => 'ᾡ', 'ᾪ' => 'ᾢ', 'ᾫ' => 'ᾣ', 'ᾬ' => 'ᾤ', 'ᾭ' => 'ᾥ', 'ᾮ' => 'ᾦ', 'ᾯ' => 'ᾧ', 'Ᾰ' => 'ᾰ', 'Ᾱ' => 'ᾱ', 'Ὰ' => 'ὰ', 'Ά' => 'ά', 'ᾼ' => 'ᾳ', 'Ὲ' => 'ὲ', 'Έ' => 'έ', 'Ὴ' => 'ὴ', 'Ή' => 'ή', 'ῌ' => 'ῃ', 'Ῐ' => 'ῐ', 'Ῑ' => 'ῑ', 'Ὶ' => 'ὶ', 'Ί' => 'ί', 'Ῠ' => 'ῠ', 'Ῡ' => 'ῡ', 'Ὺ' => 'ὺ', 'Ύ' => 'ύ', 'Ῥ' => 'ῥ', 'Ὸ' => 'ὸ', 'Ό' => 'ό', 'Ὼ' => 'ὼ', 'Ώ' => 'ώ', 'ῼ' => 'ῳ', 'Ω' => 'ω', 'K' => 'k', 'Å' => 'å', 'Ⅎ' => 'ⅎ', 'Ⅰ' => 'ⅰ', 'Ⅱ' => 'ⅱ', 'Ⅲ' => 'ⅲ', 'Ⅳ' => 'ⅳ', 'Ⅴ' => 'ⅴ', 'Ⅵ' => 'ⅵ', 'Ⅶ' => 'ⅶ', 'Ⅷ' => 'ⅷ', 'Ⅸ' => 'ⅸ', 'Ⅹ' => 'ⅹ', 'Ⅺ' => 'ⅺ', 'Ⅻ' => 'ⅻ', 'Ⅼ' => 'ⅼ', 'Ⅽ' => 'ⅽ', 'Ⅾ' => 'ⅾ', 'Ⅿ' => 'ⅿ', 'Ↄ' => 'ↄ', 'Ⓐ' => 'ⓐ', 'Ⓑ' => 'ⓑ', 'Ⓒ' => 'ⓒ', 'Ⓓ' => 'ⓓ', 'Ⓔ' => 'ⓔ', 'Ⓕ' => 'ⓕ', 'Ⓖ' => 'ⓖ', 'Ⓗ' => 'ⓗ', 'Ⓘ' => 'ⓘ', 'Ⓙ' => 'ⓙ', 'Ⓚ' => 'ⓚ', 'Ⓛ' => 'ⓛ', 'Ⓜ' => 'ⓜ', 'Ⓝ' => 'ⓝ', 'Ⓞ' => 'ⓞ', 'Ⓟ' => 'ⓟ', 'Ⓠ' => 'ⓠ', 'Ⓡ' => 'ⓡ', 'Ⓢ' => 'ⓢ', 'Ⓣ' => 'ⓣ', 'Ⓤ' => 'ⓤ', 'Ⓥ' => 'ⓥ', 'Ⓦ' => 'ⓦ', 'Ⓧ' => 'ⓧ', 'Ⓨ' => 'ⓨ', 'Ⓩ' => 'ⓩ', 'Ⰰ' => 'ⰰ', 'Ⰱ' => 'ⰱ', 'Ⰲ' => 'ⰲ', 'Ⰳ' => 'ⰳ', 'Ⰴ' => 'ⰴ', 'Ⰵ' => 'ⰵ', 'Ⰶ' => 'ⰶ', 'Ⰷ' => 'ⰷ', 'Ⰸ' => 'ⰸ', 'Ⰹ' => 'ⰹ', 'Ⰺ' => 'ⰺ', 'Ⰻ' => 'ⰻ', 'Ⰼ' => 'ⰼ', 'Ⰽ' => 'ⰽ', 'Ⰾ' => 'ⰾ', 'Ⰿ' => 'ⰿ', 'Ⱀ' => 'ⱀ', 'Ⱁ' => 'ⱁ', 'Ⱂ' => 'ⱂ', 'Ⱃ' => 'ⱃ', 'Ⱄ' => 'ⱄ', 'Ⱅ' => 'ⱅ', 'Ⱆ' => 'ⱆ', 'Ⱇ' => 'ⱇ', 'Ⱈ' => 'ⱈ', 'Ⱉ' => 'ⱉ', 'Ⱊ' => 'ⱊ', 'Ⱋ' => 'ⱋ', 'Ⱌ' => 'ⱌ', 'Ⱍ' => 'ⱍ', 'Ⱎ' => 'ⱎ', 'Ⱏ' => 'ⱏ', 'Ⱐ' => 'ⱐ', 'Ⱑ' => 'ⱑ', 'Ⱒ' => 'ⱒ', 'Ⱓ' => 'ⱓ', 'Ⱔ' => 'ⱔ', 'Ⱕ' => 'ⱕ', 'Ⱖ' => 'ⱖ', 'Ⱗ' => 'ⱗ', 'Ⱘ' => 'ⱘ', 'Ⱙ' => 'ⱙ', 'Ⱚ' => 'ⱚ', 'Ⱛ' => 'ⱛ', 'Ⱜ' => 'ⱜ', 'Ⱝ' => 'ⱝ', 'Ⱞ' => 'ⱞ', 'Ⱡ' => 'ⱡ', 'Ɫ' => 'ɫ', 'Ᵽ' => 'ᵽ', 'Ɽ' => 'ɽ', 'Ⱨ' => 'ⱨ', 'Ⱪ' => 'ⱪ', 'Ⱬ' => 'ⱬ', 'Ɑ' => 'ɑ', 'Ɱ' => 'ɱ', 'Ɐ' => 'ɐ', 'Ɒ' => 'ɒ', 'Ⱳ' => 'ⱳ', 'Ⱶ' => 'ⱶ', 'Ȿ' => 'ȿ', 'Ɀ' => 'ɀ', 'Ⲁ' => 'ⲁ', 'Ⲃ' => 'ⲃ', 'Ⲅ' => 'ⲅ', 'Ⲇ' => 'ⲇ', 'Ⲉ' => 'ⲉ', 'Ⲋ' => 'ⲋ', 'Ⲍ' => 'ⲍ', 'Ⲏ' => 'ⲏ', 'Ⲑ' => 'ⲑ', 'Ⲓ' => 'ⲓ', 'Ⲕ' => 'ⲕ', 'Ⲗ' => 'ⲗ', 'Ⲙ' => 'ⲙ', 'Ⲛ' => 'ⲛ', 'Ⲝ' => 'ⲝ', 'Ⲟ' => 'ⲟ', 'Ⲡ' => 'ⲡ', 'Ⲣ' => 'ⲣ', 'Ⲥ' => 'ⲥ', 'Ⲧ' => 'ⲧ', 'Ⲩ' => 'ⲩ', 'Ⲫ' => 'ⲫ', 'Ⲭ' => 'ⲭ', 'Ⲯ' => 'ⲯ', 'Ⲱ' => 'ⲱ', 'Ⲳ' => 'ⲳ', 'Ⲵ' => 'ⲵ', 'Ⲷ' => 'ⲷ', 'Ⲹ' => 'ⲹ', 'Ⲻ' => 'ⲻ', 'Ⲽ' => 'ⲽ', 'Ⲿ' => 'ⲿ', 'Ⳁ' => 'ⳁ', 'Ⳃ' => 'ⳃ', 'Ⳅ' => 'ⳅ', 'Ⳇ' => 'ⳇ', 'Ⳉ' => 'ⳉ', 'Ⳋ' => 'ⳋ', 'Ⳍ' => 'ⳍ', 'Ⳏ' => 'ⳏ', 'Ⳑ' => 'ⳑ', 'Ⳓ' => 'ⳓ', 'Ⳕ' => 'ⳕ', 'Ⳗ' => 'ⳗ', 'Ⳙ' => 'ⳙ', 'Ⳛ' => 'ⳛ', 'Ⳝ' => 'ⳝ', 'Ⳟ' => 'ⳟ', 'Ⳡ' => 'ⳡ', 'Ⳣ' => 'ⳣ', 'Ⳬ' => 'ⳬ', 'Ⳮ' => 'ⳮ', 'Ⳳ' => 'ⳳ', 'Ꙁ' => 'ꙁ', 'Ꙃ' => 'ꙃ', 'Ꙅ' => 'ꙅ', 'Ꙇ' => 'ꙇ', 'Ꙉ' => 'ꙉ', 'Ꙋ' => 'ꙋ', 'Ꙍ' => 'ꙍ', 'Ꙏ' => 'ꙏ', 'Ꙑ' => 'ꙑ', 'Ꙓ' => 'ꙓ', 'Ꙕ' => 'ꙕ', 'Ꙗ' => 'ꙗ', 'Ꙙ' => 'ꙙ', 'Ꙛ' => 'ꙛ', 'Ꙝ' => 'ꙝ', 'Ꙟ' => 'ꙟ', 'Ꙡ' => 'ꙡ', 'Ꙣ' => 'ꙣ', 'Ꙥ' => 'ꙥ', 'Ꙧ' => 'ꙧ', 'Ꙩ' => 'ꙩ', 'Ꙫ' => 'ꙫ', 'Ꙭ' => 'ꙭ', 'Ꚁ' => 'ꚁ', 'Ꚃ' => 'ꚃ', 'Ꚅ' => 'ꚅ', 'Ꚇ' => 'ꚇ', 'Ꚉ' => 'ꚉ', 'Ꚋ' => 'ꚋ', 'Ꚍ' => 'ꚍ', 'Ꚏ' => 'ꚏ', 'Ꚑ' => 'ꚑ', 'Ꚓ' => 'ꚓ', 'Ꚕ' => 'ꚕ', 'Ꚗ' => 'ꚗ', 'Ꚙ' => 'ꚙ', 'Ꚛ' => 'ꚛ', 'Ꜣ' => 'ꜣ', 'Ꜥ' => 'ꜥ', 'Ꜧ' => 'ꜧ', 'Ꜩ' => 'ꜩ', 'Ꜫ' => 'ꜫ', 'Ꜭ' => 'ꜭ', 'Ꜯ' => 'ꜯ', 'Ꜳ' => 'ꜳ', 'Ꜵ' => 'ꜵ', 'Ꜷ' => 'ꜷ', 'Ꜹ' => 'ꜹ', 'Ꜻ' => 'ꜻ', 'Ꜽ' => 'ꜽ', 'Ꜿ' => 'ꜿ', 'Ꝁ' => 'ꝁ', 'Ꝃ' => 'ꝃ', 'Ꝅ' => 'ꝅ', 'Ꝇ' => 'ꝇ', 'Ꝉ' => 'ꝉ', 'Ꝋ' => 'ꝋ', 'Ꝍ' => 'ꝍ', 'Ꝏ' => 'ꝏ', 'Ꝑ' => 'ꝑ', 'Ꝓ' => 'ꝓ', 'Ꝕ' => 'ꝕ', 'Ꝗ' => 'ꝗ', 'Ꝙ' => 'ꝙ', 'Ꝛ' => 'ꝛ', 'Ꝝ' => 'ꝝ', 'Ꝟ' => 'ꝟ', 'Ꝡ' => 'ꝡ', 'Ꝣ' => 'ꝣ', 'Ꝥ' => 'ꝥ', 'Ꝧ' => 'ꝧ', 'Ꝩ' => 'ꝩ', 'Ꝫ' => 'ꝫ', 'Ꝭ' => 'ꝭ', 'Ꝯ' => 'ꝯ', 'Ꝺ' => 'ꝺ', 'Ꝼ' => 'ꝼ', 'Ᵹ' => 'ᵹ', 'Ꝿ' => 'ꝿ', 'Ꞁ' => 'ꞁ', 'Ꞃ' => 'ꞃ', 'Ꞅ' => 'ꞅ', 'Ꞇ' => 'ꞇ', 'Ꞌ' => 'ꞌ', 'Ɥ' => 'ɥ', 'Ꞑ' => 'ꞑ', 'Ꞓ' => 'ꞓ', 'Ꞗ' => 'ꞗ', 'Ꞙ' => 'ꞙ', 'Ꞛ' => 'ꞛ', 'Ꞝ' => 'ꞝ', 'Ꞟ' => 'ꞟ', 'Ꞡ' => 'ꞡ', 'Ꞣ' => 'ꞣ', 'Ꞥ' => 'ꞥ', 'Ꞧ' => 'ꞧ', 'Ꞩ' => 'ꞩ', 'Ɦ' => 'ɦ', 'Ɜ' => 'ɜ', 'Ɡ' => 'ɡ', 'Ɬ' => 'ɬ', 'Ɪ' => 'ɪ', 'Ʞ' => 'ʞ', 'Ʇ' => 'ʇ', 'Ʝ' => 'ʝ', 'Ꭓ' => 'ꭓ', 'Ꞵ' => 'ꞵ', 'Ꞷ' => 'ꞷ', 'Ꞹ' => 'ꞹ', 'Ꞻ' => 'ꞻ', 'Ꞽ' => 'ꞽ', 'Ꞿ' => 'ꞿ', 'Ꟃ' => 'ꟃ', 'Ꞔ' => 'ꞔ', 'Ʂ' => 'ʂ', 'Ᶎ' => 'ᶎ', 'Ꟈ' => 'ꟈ', 'Ꟊ' => 'ꟊ', 'Ꟶ' => 'ꟶ', 'A' => 'a', 'B' => 'b', 'C' => 'c', 'D' => 'd', 'E' => 'e', 'F' => 'f', 'G' => 'g', 'H' => 'h', 'I' => 'i', 'J' => 'j', 'K' => 'k', 'L' => 'l', 'M' => 'm', 'N' => 'n', 'O' => 'o', 'P' => 'p', 'Q' => 'q', 'R' => 'r', 'S' => 's', 'T' => 't', 'U' => 'u', 'V' => 'v', 'W' => 'w', 'X' => 'x', 'Y' => 'y', 'Z' => 'z', '𐐀' => '𐐨', '𐐁' => '𐐩', '𐐂' => '𐐪', '𐐃' => '𐐫', '𐐄' => '𐐬', '𐐅' => '𐐭', '𐐆' => '𐐮', '𐐇' => '𐐯', '𐐈' => '𐐰', '𐐉' => '𐐱', '𐐊' => '𐐲', '𐐋' => '𐐳', '𐐌' => '𐐴', '𐐍' => '𐐵', '𐐎' => '𐐶', '𐐏' => '𐐷', '𐐐' => '𐐸', '𐐑' => '𐐹', '𐐒' => '𐐺', '𐐓' => '𐐻', '𐐔' => '𐐼', '𐐕' => '𐐽', '𐐖' => '𐐾', '𐐗' => '𐐿', '𐐘' => '𐑀', '𐐙' => '𐑁', '𐐚' => '𐑂', '𐐛' => '𐑃', '𐐜' => '𐑄', '𐐝' => '𐑅', '𐐞' => '𐑆', '𐐟' => '𐑇', '𐐠' => '𐑈', '𐐡' => '𐑉', '𐐢' => '𐑊', '𐐣' => '𐑋', '𐐤' => '𐑌', '𐐥' => '𐑍', '𐐦' => '𐑎', '𐐧' => '𐑏', '𐒰' => '𐓘', '𐒱' => '𐓙', '𐒲' => '𐓚', '𐒳' => '𐓛', '𐒴' => '𐓜', '𐒵' => '𐓝', '𐒶' => '𐓞', '𐒷' => '𐓟', '𐒸' => '𐓠', '𐒹' => '𐓡', '𐒺' => '𐓢', '𐒻' => '𐓣', '𐒼' => '𐓤', '𐒽' => '𐓥', '𐒾' => '𐓦', '𐒿' => '𐓧', '𐓀' => '𐓨', '𐓁' => '𐓩', '𐓂' => '𐓪', '𐓃' => '𐓫', '𐓄' => '𐓬', '𐓅' => '𐓭', '𐓆' => '𐓮', '𐓇' => '𐓯', '𐓈' => '𐓰', '𐓉' => '𐓱', '𐓊' => '𐓲', '𐓋' => '𐓳', '𐓌' => '𐓴', '𐓍' => '𐓵', '𐓎' => '𐓶', '𐓏' => '𐓷', '𐓐' => '𐓸', '𐓑' => '𐓹', '𐓒' => '𐓺', '𐓓' => '𐓻', '𐲀' => '𐳀', '𐲁' => '𐳁', '𐲂' => '𐳂', '𐲃' => '𐳃', '𐲄' => '𐳄', '𐲅' => '𐳅', '𐲆' => '𐳆', '𐲇' => '𐳇', '𐲈' => '𐳈', '𐲉' => '𐳉', '𐲊' => '𐳊', '𐲋' => '𐳋', '𐲌' => '𐳌', '𐲍' => '𐳍', '𐲎' => '𐳎', '𐲏' => '𐳏', '𐲐' => '𐳐', '𐲑' => '𐳑', '𐲒' => '𐳒', '𐲓' => '𐳓', '𐲔' => '𐳔', '𐲕' => '𐳕', '𐲖' => '𐳖', '𐲗' => '𐳗', '𐲘' => '𐳘', '𐲙' => '𐳙', '𐲚' => '𐳚', '𐲛' => '𐳛', '𐲜' => '𐳜', '𐲝' => '𐳝', '𐲞' => '𐳞', '𐲟' => '𐳟', '𐲠' => '𐳠', '𐲡' => '𐳡', '𐲢' => '𐳢', '𐲣' => '𐳣', '𐲤' => '𐳤', '𐲥' => '𐳥', '𐲦' => '𐳦', '𐲧' => '𐳧', '𐲨' => '𐳨', '𐲩' => '𐳩', '𐲪' => '𐳪', '𐲫' => '𐳫', '𐲬' => '𐳬', '𐲭' => '𐳭', '𐲮' => '𐳮', '𐲯' => '𐳯', '𐲰' => '𐳰', '𐲱' => '𐳱', '𐲲' => '𐳲', '𑢠' => '𑣀', '𑢡' => '𑣁', '𑢢' => '𑣂', '𑢣' => '𑣃', '𑢤' => '𑣄', '𑢥' => '𑣅', '𑢦' => '𑣆', '𑢧' => '𑣇', '𑢨' => '𑣈', '𑢩' => '𑣉', '𑢪' => '𑣊', '𑢫' => '𑣋', '𑢬' => '𑣌', '𑢭' => '𑣍', '𑢮' => '𑣎', '𑢯' => '𑣏', '𑢰' => '𑣐', '𑢱' => '𑣑', '𑢲' => '𑣒', '𑢳' => '𑣓', '𑢴' => '𑣔', '𑢵' => '𑣕', '𑢶' => '𑣖', '𑢷' => '𑣗', '𑢸' => '𑣘', '𑢹' => '𑣙', '𑢺' => '𑣚', '𑢻' => '𑣛', '𑢼' => '𑣜', '𑢽' => '𑣝', '𑢾' => '𑣞', '𑢿' => '𑣟', '𖹀' => '𖹠', '𖹁' => '𖹡', '𖹂' => '𖹢', '𖹃' => '𖹣', '𖹄' => '𖹤', '𖹅' => '𖹥', '𖹆' => '𖹦', '𖹇' => '𖹧', '𖹈' => '𖹨', '𖹉' => '𖹩', '𖹊' => '𖹪', '𖹋' => '𖹫', '𖹌' => '𖹬', '𖹍' => '𖹭', '𖹎' => '𖹮', '𖹏' => '𖹯', '𖹐' => '𖹰', '𖹑' => '𖹱', '𖹒' => '𖹲', '𖹓' => '𖹳', '𖹔' => '𖹴', '𖹕' => '𖹵', '𖹖' => '𖹶', '𖹗' => '𖹷', '𖹘' => '𖹸', '𖹙' => '𖹹', '𖹚' => '𖹺', '𖹛' => '𖹻', '𖹜' => '𖹼', '𖹝' => '𖹽', '𖹞' => '𖹾', '𖹟' => '𖹿', '𞤀' => '𞤢', '𞤁' => '𞤣', '𞤂' => '𞤤', '𞤃' => '𞤥', '𞤄' => '𞤦', '𞤅' => '𞤧', '𞤆' => '𞤨', '𞤇' => '𞤩', '𞤈' => '𞤪', '𞤉' => '𞤫', '𞤊' => '𞤬', '𞤋' => '𞤭', '𞤌' => '𞤮', '𞤍' => '𞤯', '𞤎' => '𞤰', '𞤏' => '𞤱', '𞤐' => '𞤲', '𞤑' => '𞤳', '𞤒' => '𞤴', '𞤓' => '𞤵', '𞤔' => '𞤶', '𞤕' => '𞤷', '𞤖' => '𞤸', '𞤗' => '𞤹', '𞤘' => '𞤺', '𞤙' => '𞤻', '𞤚' => '𞤼', '𞤛' => '𞤽', '𞤜' => '𞤾', '𞤝' => '𞤿', '𞤞' => '𞥀', '𞤟' => '𞥁', '𞤠' => '𞥂', '𞤡' => '𞥃'); diff --git a/vendor-bundle/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php b/vendor-bundle/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php new file mode 100644 index 000000000..b5dde631b --- /dev/null +++ b/vendor-bundle/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php @@ -0,0 +1,6 @@ + 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D', 'e' => 'E', 'f' => 'F', 'g' => 'G', 'h' => 'H', 'i' => 'I', 'j' => 'J', 'k' => 'K', 'l' => 'L', 'm' => 'M', 'n' => 'N', 'o' => 'O', 'p' => 'P', 'q' => 'Q', 'r' => 'R', 's' => 'S', 't' => 'T', 'u' => 'U', 'v' => 'V', 'w' => 'W', 'x' => 'X', 'y' => 'Y', 'z' => 'Z', 'µ' => 'Μ', 'à' => 'À', 'á' => 'Á', 'â' => 'Â', 'ã' => 'Ã', 'ä' => 'Ä', 'å' => 'Å', 'æ' => 'Æ', 'ç' => 'Ç', 'è' => 'È', 'é' => 'É', 'ê' => 'Ê', 'ë' => 'Ë', 'ì' => 'Ì', 'í' => 'Í', 'î' => 'Î', 'ï' => 'Ï', 'ð' => 'Ð', 'ñ' => 'Ñ', 'ò' => 'Ò', 'ó' => 'Ó', 'ô' => 'Ô', 'õ' => 'Õ', 'ö' => 'Ö', 'ø' => 'Ø', 'ù' => 'Ù', 'ú' => 'Ú', 'û' => 'Û', 'ü' => 'Ü', 'ý' => 'Ý', 'þ' => 'Þ', 'ÿ' => 'Ÿ', 'ā' => 'Ā', 'ă' => 'Ă', 'ą' => 'Ą', 'ć' => 'Ć', 'ĉ' => 'Ĉ', 'ċ' => 'Ċ', 'č' => 'Č', 'ď' => 'Ď', 'đ' => 'Đ', 'ē' => 'Ē', 'ĕ' => 'Ĕ', 'ė' => 'Ė', 'ę' => 'Ę', 'ě' => 'Ě', 'ĝ' => 'Ĝ', 'ğ' => 'Ğ', 'ġ' => 'Ġ', 'ģ' => 'Ģ', 'ĥ' => 'Ĥ', 'ħ' => 'Ħ', 'ĩ' => 'Ĩ', 'ī' => 'Ī', 'ĭ' => 'Ĭ', 'į' => 'Į', 'ı' => 'I', 'ij' => 'IJ', 'ĵ' => 'Ĵ', 'ķ' => 'Ķ', 'ĺ' => 'Ĺ', 'ļ' => 'Ļ', 'ľ' => 'Ľ', 'ŀ' => 'Ŀ', 'ł' => 'Ł', 'ń' => 'Ń', 'ņ' => 'Ņ', 'ň' => 'Ň', 'ŋ' => 'Ŋ', 'ō' => 'Ō', 'ŏ' => 'Ŏ', 'ő' => 'Ő', 'œ' => 'Œ', 'ŕ' => 'Ŕ', 'ŗ' => 'Ŗ', 'ř' => 'Ř', 'ś' => 'Ś', 'ŝ' => 'Ŝ', 'ş' => 'Ş', 'š' => 'Š', 'ţ' => 'Ţ', 'ť' => 'Ť', 'ŧ' => 'Ŧ', 'ũ' => 'Ũ', 'ū' => 'Ū', 'ŭ' => 'Ŭ', 'ů' => 'Ů', 'ű' => 'Ű', 'ų' => 'Ų', 'ŵ' => 'Ŵ', 'ŷ' => 'Ŷ', 'ź' => 'Ź', 'ż' => 'Ż', 'ž' => 'Ž', 'ſ' => 'S', 'ƀ' => 'Ƀ', 'ƃ' => 'Ƃ', 'ƅ' => 'Ƅ', 'ƈ' => 'Ƈ', 'ƌ' => 'Ƌ', 'ƒ' => 'Ƒ', 'ƕ' => 'Ƕ', 'ƙ' => 'Ƙ', 'ƚ' => 'Ƚ', 'ƞ' => 'Ƞ', 'ơ' => 'Ơ', 'ƣ' => 'Ƣ', 'ƥ' => 'Ƥ', 'ƨ' => 'Ƨ', 'ƭ' => 'Ƭ', 'ư' => 'Ư', 'ƴ' => 'Ƴ', 'ƶ' => 'Ƶ', 'ƹ' => 'Ƹ', 'ƽ' => 'Ƽ', 'ƿ' => 'Ƿ', 'Dž' => 'DŽ', 'dž' => 'DŽ', 'Lj' => 'LJ', 'lj' => 'LJ', 'Nj' => 'NJ', 'nj' => 'NJ', 'ǎ' => 'Ǎ', 'ǐ' => 'Ǐ', 'ǒ' => 'Ǒ', 'ǔ' => 'Ǔ', 'ǖ' => 'Ǖ', 'ǘ' => 'Ǘ', 'ǚ' => 'Ǚ', 'ǜ' => 'Ǜ', 'ǝ' => 'Ǝ', 'ǟ' => 'Ǟ', 'ǡ' => 'Ǡ', 'ǣ' => 'Ǣ', 'ǥ' => 'Ǥ', 'ǧ' => 'Ǧ', 'ǩ' => 'Ǩ', 'ǫ' => 'Ǫ', 'ǭ' => 'Ǭ', 'ǯ' => 'Ǯ', 'Dz' => 'DZ', 'dz' => 'DZ', 'ǵ' => 'Ǵ', 'ǹ' => 'Ǹ', 'ǻ' => 'Ǻ', 'ǽ' => 'Ǽ', 'ǿ' => 'Ǿ', 'ȁ' => 'Ȁ', 'ȃ' => 'Ȃ', 'ȅ' => 'Ȅ', 'ȇ' => 'Ȇ', 'ȉ' => 'Ȉ', 'ȋ' => 'Ȋ', 'ȍ' => 'Ȍ', 'ȏ' => 'Ȏ', 'ȑ' => 'Ȑ', 'ȓ' => 'Ȓ', 'ȕ' => 'Ȕ', 'ȗ' => 'Ȗ', 'ș' => 'Ș', 'ț' => 'Ț', 'ȝ' => 'Ȝ', 'ȟ' => 'Ȟ', 'ȣ' => 'Ȣ', 'ȥ' => 'Ȥ', 'ȧ' => 'Ȧ', 'ȩ' => 'Ȩ', 'ȫ' => 'Ȫ', 'ȭ' => 'Ȭ', 'ȯ' => 'Ȯ', 'ȱ' => 'Ȱ', 'ȳ' => 'Ȳ', 'ȼ' => 'Ȼ', 'ȿ' => 'Ȿ', 'ɀ' => 'Ɀ', 'ɂ' => 'Ɂ', 'ɇ' => 'Ɇ', 'ɉ' => 'Ɉ', 'ɋ' => 'Ɋ', 'ɍ' => 'Ɍ', 'ɏ' => 'Ɏ', 'ɐ' => 'Ɐ', 'ɑ' => 'Ɑ', 'ɒ' => 'Ɒ', 'ɓ' => 'Ɓ', 'ɔ' => 'Ɔ', 'ɖ' => 'Ɖ', 'ɗ' => 'Ɗ', 'ə' => 'Ə', 'ɛ' => 'Ɛ', 'ɜ' => 'Ɜ', 'ɠ' => 'Ɠ', 'ɡ' => 'Ɡ', 'ɣ' => 'Ɣ', 'ɥ' => 'Ɥ', 'ɦ' => 'Ɦ', 'ɨ' => 'Ɨ', 'ɩ' => 'Ɩ', 'ɪ' => 'Ɪ', 'ɫ' => 'Ɫ', 'ɬ' => 'Ɬ', 'ɯ' => 'Ɯ', 'ɱ' => 'Ɱ', 'ɲ' => 'Ɲ', 'ɵ' => 'Ɵ', 'ɽ' => 'Ɽ', 'ʀ' => 'Ʀ', 'ʂ' => 'Ʂ', 'ʃ' => 'Ʃ', 'ʇ' => 'Ʇ', 'ʈ' => 'Ʈ', 'ʉ' => 'Ʉ', 'ʊ' => 'Ʊ', 'ʋ' => 'Ʋ', 'ʌ' => 'Ʌ', 'ʒ' => 'Ʒ', 'ʝ' => 'Ʝ', 'ʞ' => 'Ʞ', 'ͅ' => 'Ι', 'ͱ' => 'Ͱ', 'ͳ' => 'Ͳ', 'ͷ' => 'Ͷ', 'ͻ' => 'Ͻ', 'ͼ' => 'Ͼ', 'ͽ' => 'Ͽ', 'ά' => 'Ά', 'έ' => 'Έ', 'ή' => 'Ή', 'ί' => 'Ί', 'α' => 'Α', 'β' => 'Β', 'γ' => 'Γ', 'δ' => 'Δ', 'ε' => 'Ε', 'ζ' => 'Ζ', 'η' => 'Η', 'θ' => 'Θ', 'ι' => 'Ι', 'κ' => 'Κ', 'λ' => 'Λ', 'μ' => 'Μ', 'ν' => 'Ν', 'ξ' => 'Ξ', 'ο' => 'Ο', 'π' => 'Π', 'ρ' => 'Ρ', 'ς' => 'Σ', 'σ' => 'Σ', 'τ' => 'Τ', 'υ' => 'Υ', 'φ' => 'Φ', 'χ' => 'Χ', 'ψ' => 'Ψ', 'ω' => 'Ω', 'ϊ' => 'Ϊ', 'ϋ' => 'Ϋ', 'ό' => 'Ό', 'ύ' => 'Ύ', 'ώ' => 'Ώ', 'ϐ' => 'Β', 'ϑ' => 'Θ', 'ϕ' => 'Φ', 'ϖ' => 'Π', 'ϗ' => 'Ϗ', 'ϙ' => 'Ϙ', 'ϛ' => 'Ϛ', 'ϝ' => 'Ϝ', 'ϟ' => 'Ϟ', 'ϡ' => 'Ϡ', 'ϣ' => 'Ϣ', 'ϥ' => 'Ϥ', 'ϧ' => 'Ϧ', 'ϩ' => 'Ϩ', 'ϫ' => 'Ϫ', 'ϭ' => 'Ϭ', 'ϯ' => 'Ϯ', 'ϰ' => 'Κ', 'ϱ' => 'Ρ', 'ϲ' => 'Ϲ', 'ϳ' => 'Ϳ', 'ϵ' => 'Ε', 'ϸ' => 'Ϸ', 'ϻ' => 'Ϻ', 'а' => 'А', 'б' => 'Б', 'в' => 'В', 'г' => 'Г', 'д' => 'Д', 'е' => 'Е', 'ж' => 'Ж', 'з' => 'З', 'и' => 'И', 'й' => 'Й', 'к' => 'К', 'л' => 'Л', 'м' => 'М', 'н' => 'Н', 'о' => 'О', 'п' => 'П', 'р' => 'Р', 'с' => 'С', 'т' => 'Т', 'у' => 'У', 'ф' => 'Ф', 'х' => 'Х', 'ц' => 'Ц', 'ч' => 'Ч', 'ш' => 'Ш', 'щ' => 'Щ', 'ъ' => 'Ъ', 'ы' => 'Ы', 'ь' => 'Ь', 'э' => 'Э', 'ю' => 'Ю', 'я' => 'Я', 'ѐ' => 'Ѐ', 'ё' => 'Ё', 'ђ' => 'Ђ', 'ѓ' => 'Ѓ', 'є' => 'Є', 'ѕ' => 'Ѕ', 'і' => 'І', 'ї' => 'Ї', 'ј' => 'Ј', 'љ' => 'Љ', 'њ' => 'Њ', 'ћ' => 'Ћ', 'ќ' => 'Ќ', 'ѝ' => 'Ѝ', 'ў' => 'Ў', 'џ' => 'Џ', 'ѡ' => 'Ѡ', 'ѣ' => 'Ѣ', 'ѥ' => 'Ѥ', 'ѧ' => 'Ѧ', 'ѩ' => 'Ѩ', 'ѫ' => 'Ѫ', 'ѭ' => 'Ѭ', 'ѯ' => 'Ѯ', 'ѱ' => 'Ѱ', 'ѳ' => 'Ѳ', 'ѵ' => 'Ѵ', 'ѷ' => 'Ѷ', 'ѹ' => 'Ѹ', 'ѻ' => 'Ѻ', 'ѽ' => 'Ѽ', 'ѿ' => 'Ѿ', 'ҁ' => 'Ҁ', 'ҋ' => 'Ҋ', 'ҍ' => 'Ҍ', 'ҏ' => 'Ҏ', 'ґ' => 'Ґ', 'ғ' => 'Ғ', 'ҕ' => 'Ҕ', 'җ' => 'Җ', 'ҙ' => 'Ҙ', 'қ' => 'Қ', 'ҝ' => 'Ҝ', 'ҟ' => 'Ҟ', 'ҡ' => 'Ҡ', 'ң' => 'Ң', 'ҥ' => 'Ҥ', 'ҧ' => 'Ҧ', 'ҩ' => 'Ҩ', 'ҫ' => 'Ҫ', 'ҭ' => 'Ҭ', 'ү' => 'Ү', 'ұ' => 'Ұ', 'ҳ' => 'Ҳ', 'ҵ' => 'Ҵ', 'ҷ' => 'Ҷ', 'ҹ' => 'Ҹ', 'һ' => 'Һ', 'ҽ' => 'Ҽ', 'ҿ' => 'Ҿ', 'ӂ' => 'Ӂ', 'ӄ' => 'Ӄ', 'ӆ' => 'Ӆ', 'ӈ' => 'Ӈ', 'ӊ' => 'Ӊ', 'ӌ' => 'Ӌ', 'ӎ' => 'Ӎ', 'ӏ' => 'Ӏ', 'ӑ' => 'Ӑ', 'ӓ' => 'Ӓ', 'ӕ' => 'Ӕ', 'ӗ' => 'Ӗ', 'ә' => 'Ә', 'ӛ' => 'Ӛ', 'ӝ' => 'Ӝ', 'ӟ' => 'Ӟ', 'ӡ' => 'Ӡ', 'ӣ' => 'Ӣ', 'ӥ' => 'Ӥ', 'ӧ' => 'Ӧ', 'ө' => 'Ө', 'ӫ' => 'Ӫ', 'ӭ' => 'Ӭ', 'ӯ' => 'Ӯ', 'ӱ' => 'Ӱ', 'ӳ' => 'Ӳ', 'ӵ' => 'Ӵ', 'ӷ' => 'Ӷ', 'ӹ' => 'Ӹ', 'ӻ' => 'Ӻ', 'ӽ' => 'Ӽ', 'ӿ' => 'Ӿ', 'ԁ' => 'Ԁ', 'ԃ' => 'Ԃ', 'ԅ' => 'Ԅ', 'ԇ' => 'Ԇ', 'ԉ' => 'Ԉ', 'ԋ' => 'Ԋ', 'ԍ' => 'Ԍ', 'ԏ' => 'Ԏ', 'ԑ' => 'Ԑ', 'ԓ' => 'Ԓ', 'ԕ' => 'Ԕ', 'ԗ' => 'Ԗ', 'ԙ' => 'Ԙ', 'ԛ' => 'Ԛ', 'ԝ' => 'Ԝ', 'ԟ' => 'Ԟ', 'ԡ' => 'Ԡ', 'ԣ' => 'Ԣ', 'ԥ' => 'Ԥ', 'ԧ' => 'Ԧ', 'ԩ' => 'Ԩ', 'ԫ' => 'Ԫ', 'ԭ' => 'Ԭ', 'ԯ' => 'Ԯ', 'ա' => 'Ա', 'բ' => 'Բ', 'գ' => 'Գ', 'դ' => 'Դ', 'ե' => 'Ե', 'զ' => 'Զ', 'է' => 'Է', 'ը' => 'Ը', 'թ' => 'Թ', 'ժ' => 'Ժ', 'ի' => 'Ի', 'լ' => 'Լ', 'խ' => 'Խ', 'ծ' => 'Ծ', 'կ' => 'Կ', 'հ' => 'Հ', 'ձ' => 'Ձ', 'ղ' => 'Ղ', 'ճ' => 'Ճ', 'մ' => 'Մ', 'յ' => 'Յ', 'ն' => 'Ն', 'շ' => 'Շ', 'ո' => 'Ո', 'չ' => 'Չ', 'պ' => 'Պ', 'ջ' => 'Ջ', 'ռ' => 'Ռ', 'ս' => 'Ս', 'վ' => 'Վ', 'տ' => 'Տ', 'ր' => 'Ր', 'ց' => 'Ց', 'ւ' => 'Ւ', 'փ' => 'Փ', 'ք' => 'Ք', 'օ' => 'Օ', 'ֆ' => 'Ֆ', 'ა' => 'Ა', 'ბ' => 'Ბ', 'გ' => 'Გ', 'დ' => 'Დ', 'ე' => 'Ე', 'ვ' => 'Ვ', 'ზ' => 'Ზ', 'თ' => 'Თ', 'ი' => 'Ი', 'კ' => 'Კ', 'ლ' => 'Ლ', 'მ' => 'Მ', 'ნ' => 'Ნ', 'ო' => 'Ო', 'პ' => 'Პ', 'ჟ' => 'Ჟ', 'რ' => 'Რ', 'ს' => 'Ს', 'ტ' => 'Ტ', 'უ' => 'Უ', 'ფ' => 'Ფ', 'ქ' => 'Ქ', 'ღ' => 'Ღ', 'ყ' => 'Ყ', 'შ' => 'Შ', 'ჩ' => 'Ჩ', 'ც' => 'Ც', 'ძ' => 'Ძ', 'წ' => 'Წ', 'ჭ' => 'Ჭ', 'ხ' => 'Ხ', 'ჯ' => 'Ჯ', 'ჰ' => 'Ჰ', 'ჱ' => 'Ჱ', 'ჲ' => 'Ჲ', 'ჳ' => 'Ჳ', 'ჴ' => 'Ჴ', 'ჵ' => 'Ჵ', 'ჶ' => 'Ჶ', 'ჷ' => 'Ჷ', 'ჸ' => 'Ჸ', 'ჹ' => 'Ჹ', 'ჺ' => 'Ჺ', 'ჽ' => 'Ჽ', 'ჾ' => 'Ჾ', 'ჿ' => 'Ჿ', 'ᏸ' => 'Ᏸ', 'ᏹ' => 'Ᏹ', 'ᏺ' => 'Ᏺ', 'ᏻ' => 'Ᏻ', 'ᏼ' => 'Ᏼ', 'ᏽ' => 'Ᏽ', 'ᲀ' => 'В', 'ᲁ' => 'Д', 'ᲂ' => 'О', 'ᲃ' => 'С', 'ᲄ' => 'Т', 'ᲅ' => 'Т', 'ᲆ' => 'Ъ', 'ᲇ' => 'Ѣ', 'ᲈ' => 'Ꙋ', 'ᵹ' => 'Ᵹ', 'ᵽ' => 'Ᵽ', 'ᶎ' => 'Ᶎ', 'ḁ' => 'Ḁ', 'ḃ' => 'Ḃ', 'ḅ' => 'Ḅ', 'ḇ' => 'Ḇ', 'ḉ' => 'Ḉ', 'ḋ' => 'Ḋ', 'ḍ' => 'Ḍ', 'ḏ' => 'Ḏ', 'ḑ' => 'Ḑ', 'ḓ' => 'Ḓ', 'ḕ' => 'Ḕ', 'ḗ' => 'Ḗ', 'ḙ' => 'Ḙ', 'ḛ' => 'Ḛ', 'ḝ' => 'Ḝ', 'ḟ' => 'Ḟ', 'ḡ' => 'Ḡ', 'ḣ' => 'Ḣ', 'ḥ' => 'Ḥ', 'ḧ' => 'Ḧ', 'ḩ' => 'Ḩ', 'ḫ' => 'Ḫ', 'ḭ' => 'Ḭ', 'ḯ' => 'Ḯ', 'ḱ' => 'Ḱ', 'ḳ' => 'Ḳ', 'ḵ' => 'Ḵ', 'ḷ' => 'Ḷ', 'ḹ' => 'Ḹ', 'ḻ' => 'Ḻ', 'ḽ' => 'Ḽ', 'ḿ' => 'Ḿ', 'ṁ' => 'Ṁ', 'ṃ' => 'Ṃ', 'ṅ' => 'Ṅ', 'ṇ' => 'Ṇ', 'ṉ' => 'Ṉ', 'ṋ' => 'Ṋ', 'ṍ' => 'Ṍ', 'ṏ' => 'Ṏ', 'ṑ' => 'Ṑ', 'ṓ' => 'Ṓ', 'ṕ' => 'Ṕ', 'ṗ' => 'Ṗ', 'ṙ' => 'Ṙ', 'ṛ' => 'Ṛ', 'ṝ' => 'Ṝ', 'ṟ' => 'Ṟ', 'ṡ' => 'Ṡ', 'ṣ' => 'Ṣ', 'ṥ' => 'Ṥ', 'ṧ' => 'Ṧ', 'ṩ' => 'Ṩ', 'ṫ' => 'Ṫ', 'ṭ' => 'Ṭ', 'ṯ' => 'Ṯ', 'ṱ' => 'Ṱ', 'ṳ' => 'Ṳ', 'ṵ' => 'Ṵ', 'ṷ' => 'Ṷ', 'ṹ' => 'Ṹ', 'ṻ' => 'Ṻ', 'ṽ' => 'Ṽ', 'ṿ' => 'Ṿ', 'ẁ' => 'Ẁ', 'ẃ' => 'Ẃ', 'ẅ' => 'Ẅ', 'ẇ' => 'Ẇ', 'ẉ' => 'Ẉ', 'ẋ' => 'Ẋ', 'ẍ' => 'Ẍ', 'ẏ' => 'Ẏ', 'ẑ' => 'Ẑ', 'ẓ' => 'Ẓ', 'ẕ' => 'Ẕ', 'ẛ' => 'Ṡ', 'ạ' => 'Ạ', 'ả' => 'Ả', 'ấ' => 'Ấ', 'ầ' => 'Ầ', 'ẩ' => 'Ẩ', 'ẫ' => 'Ẫ', 'ậ' => 'Ậ', 'ắ' => 'Ắ', 'ằ' => 'Ằ', 'ẳ' => 'Ẳ', 'ẵ' => 'Ẵ', 'ặ' => 'Ặ', 'ẹ' => 'Ẹ', 'ẻ' => 'Ẻ', 'ẽ' => 'Ẽ', 'ế' => 'Ế', 'ề' => 'Ề', 'ể' => 'Ể', 'ễ' => 'Ễ', 'ệ' => 'Ệ', 'ỉ' => 'Ỉ', 'ị' => 'Ị', 'ọ' => 'Ọ', 'ỏ' => 'Ỏ', 'ố' => 'Ố', 'ồ' => 'Ồ', 'ổ' => 'Ổ', 'ỗ' => 'Ỗ', 'ộ' => 'Ộ', 'ớ' => 'Ớ', 'ờ' => 'Ờ', 'ở' => 'Ở', 'ỡ' => 'Ỡ', 'ợ' => 'Ợ', 'ụ' => 'Ụ', 'ủ' => 'Ủ', 'ứ' => 'Ứ', 'ừ' => 'Ừ', 'ử' => 'Ử', 'ữ' => 'Ữ', 'ự' => 'Ự', 'ỳ' => 'Ỳ', 'ỵ' => 'Ỵ', 'ỷ' => 'Ỷ', 'ỹ' => 'Ỹ', 'ỻ' => 'Ỻ', 'ỽ' => 'Ỽ', 'ỿ' => 'Ỿ', 'ἀ' => 'Ἀ', 'ἁ' => 'Ἁ', 'ἂ' => 'Ἂ', 'ἃ' => 'Ἃ', 'ἄ' => 'Ἄ', 'ἅ' => 'Ἅ', 'ἆ' => 'Ἆ', 'ἇ' => 'Ἇ', 'ἐ' => 'Ἐ', 'ἑ' => 'Ἑ', 'ἒ' => 'Ἒ', 'ἓ' => 'Ἓ', 'ἔ' => 'Ἔ', 'ἕ' => 'Ἕ', 'ἠ' => 'Ἠ', 'ἡ' => 'Ἡ', 'ἢ' => 'Ἢ', 'ἣ' => 'Ἣ', 'ἤ' => 'Ἤ', 'ἥ' => 'Ἥ', 'ἦ' => 'Ἦ', 'ἧ' => 'Ἧ', 'ἰ' => 'Ἰ', 'ἱ' => 'Ἱ', 'ἲ' => 'Ἲ', 'ἳ' => 'Ἳ', 'ἴ' => 'Ἴ', 'ἵ' => 'Ἵ', 'ἶ' => 'Ἶ', 'ἷ' => 'Ἷ', 'ὀ' => 'Ὀ', 'ὁ' => 'Ὁ', 'ὂ' => 'Ὂ', 'ὃ' => 'Ὃ', 'ὄ' => 'Ὄ', 'ὅ' => 'Ὅ', 'ὑ' => 'Ὑ', 'ὓ' => 'Ὓ', 'ὕ' => 'Ὕ', 'ὗ' => 'Ὗ', 'ὠ' => 'Ὠ', 'ὡ' => 'Ὡ', 'ὢ' => 'Ὢ', 'ὣ' => 'Ὣ', 'ὤ' => 'Ὤ', 'ὥ' => 'Ὥ', 'ὦ' => 'Ὦ', 'ὧ' => 'Ὧ', 'ὰ' => 'Ὰ', 'ά' => 'Ά', 'ὲ' => 'Ὲ', 'έ' => 'Έ', 'ὴ' => 'Ὴ', 'ή' => 'Ή', 'ὶ' => 'Ὶ', 'ί' => 'Ί', 'ὸ' => 'Ὸ', 'ό' => 'Ό', 'ὺ' => 'Ὺ', 'ύ' => 'Ύ', 'ὼ' => 'Ὼ', 'ώ' => 'Ώ', 'ᾀ' => 'ἈΙ', 'ᾁ' => 'ἉΙ', 'ᾂ' => 'ἊΙ', 'ᾃ' => 'ἋΙ', 'ᾄ' => 'ἌΙ', 'ᾅ' => 'ἍΙ', 'ᾆ' => 'ἎΙ', 'ᾇ' => 'ἏΙ', 'ᾐ' => 'ἨΙ', 'ᾑ' => 'ἩΙ', 'ᾒ' => 'ἪΙ', 'ᾓ' => 'ἫΙ', 'ᾔ' => 'ἬΙ', 'ᾕ' => 'ἭΙ', 'ᾖ' => 'ἮΙ', 'ᾗ' => 'ἯΙ', 'ᾠ' => 'ὨΙ', 'ᾡ' => 'ὩΙ', 'ᾢ' => 'ὪΙ', 'ᾣ' => 'ὫΙ', 'ᾤ' => 'ὬΙ', 'ᾥ' => 'ὭΙ', 'ᾦ' => 'ὮΙ', 'ᾧ' => 'ὯΙ', 'ᾰ' => 'Ᾰ', 'ᾱ' => 'Ᾱ', 'ᾳ' => 'ΑΙ', 'ι' => 'Ι', 'ῃ' => 'ΗΙ', 'ῐ' => 'Ῐ', 'ῑ' => 'Ῑ', 'ῠ' => 'Ῠ', 'ῡ' => 'Ῡ', 'ῥ' => 'Ῥ', 'ῳ' => 'ΩΙ', 'ⅎ' => 'Ⅎ', 'ⅰ' => 'Ⅰ', 'ⅱ' => 'Ⅱ', 'ⅲ' => 'Ⅲ', 'ⅳ' => 'Ⅳ', 'ⅴ' => 'Ⅴ', 'ⅵ' => 'Ⅵ', 'ⅶ' => 'Ⅶ', 'ⅷ' => 'Ⅷ', 'ⅸ' => 'Ⅸ', 'ⅹ' => 'Ⅹ', 'ⅺ' => 'Ⅺ', 'ⅻ' => 'Ⅻ', 'ⅼ' => 'Ⅼ', 'ⅽ' => 'Ⅽ', 'ⅾ' => 'Ⅾ', 'ⅿ' => 'Ⅿ', 'ↄ' => 'Ↄ', 'ⓐ' => 'Ⓐ', 'ⓑ' => 'Ⓑ', 'ⓒ' => 'Ⓒ', 'ⓓ' => 'Ⓓ', 'ⓔ' => 'Ⓔ', 'ⓕ' => 'Ⓕ', 'ⓖ' => 'Ⓖ', 'ⓗ' => 'Ⓗ', 'ⓘ' => 'Ⓘ', 'ⓙ' => 'Ⓙ', 'ⓚ' => 'Ⓚ', 'ⓛ' => 'Ⓛ', 'ⓜ' => 'Ⓜ', 'ⓝ' => 'Ⓝ', 'ⓞ' => 'Ⓞ', 'ⓟ' => 'Ⓟ', 'ⓠ' => 'Ⓠ', 'ⓡ' => 'Ⓡ', 'ⓢ' => 'Ⓢ', 'ⓣ' => 'Ⓣ', 'ⓤ' => 'Ⓤ', 'ⓥ' => 'Ⓥ', 'ⓦ' => 'Ⓦ', 'ⓧ' => 'Ⓧ', 'ⓨ' => 'Ⓨ', 'ⓩ' => 'Ⓩ', 'ⰰ' => 'Ⰰ', 'ⰱ' => 'Ⰱ', 'ⰲ' => 'Ⰲ', 'ⰳ' => 'Ⰳ', 'ⰴ' => 'Ⰴ', 'ⰵ' => 'Ⰵ', 'ⰶ' => 'Ⰶ', 'ⰷ' => 'Ⰷ', 'ⰸ' => 'Ⰸ', 'ⰹ' => 'Ⰹ', 'ⰺ' => 'Ⰺ', 'ⰻ' => 'Ⰻ', 'ⰼ' => 'Ⰼ', 'ⰽ' => 'Ⰽ', 'ⰾ' => 'Ⰾ', 'ⰿ' => 'Ⰿ', 'ⱀ' => 'Ⱀ', 'ⱁ' => 'Ⱁ', 'ⱂ' => 'Ⱂ', 'ⱃ' => 'Ⱃ', 'ⱄ' => 'Ⱄ', 'ⱅ' => 'Ⱅ', 'ⱆ' => 'Ⱆ', 'ⱇ' => 'Ⱇ', 'ⱈ' => 'Ⱈ', 'ⱉ' => 'Ⱉ', 'ⱊ' => 'Ⱊ', 'ⱋ' => 'Ⱋ', 'ⱌ' => 'Ⱌ', 'ⱍ' => 'Ⱍ', 'ⱎ' => 'Ⱎ', 'ⱏ' => 'Ⱏ', 'ⱐ' => 'Ⱐ', 'ⱑ' => 'Ⱑ', 'ⱒ' => 'Ⱒ', 'ⱓ' => 'Ⱓ', 'ⱔ' => 'Ⱔ', 'ⱕ' => 'Ⱕ', 'ⱖ' => 'Ⱖ', 'ⱗ' => 'Ⱗ', 'ⱘ' => 'Ⱘ', 'ⱙ' => 'Ⱙ', 'ⱚ' => 'Ⱚ', 'ⱛ' => 'Ⱛ', 'ⱜ' => 'Ⱜ', 'ⱝ' => 'Ⱝ', 'ⱞ' => 'Ⱞ', 'ⱡ' => 'Ⱡ', 'ⱥ' => 'Ⱥ', 'ⱦ' => 'Ⱦ', 'ⱨ' => 'Ⱨ', 'ⱪ' => 'Ⱪ', 'ⱬ' => 'Ⱬ', 'ⱳ' => 'Ⱳ', 'ⱶ' => 'Ⱶ', 'ⲁ' => 'Ⲁ', 'ⲃ' => 'Ⲃ', 'ⲅ' => 'Ⲅ', 'ⲇ' => 'Ⲇ', 'ⲉ' => 'Ⲉ', 'ⲋ' => 'Ⲋ', 'ⲍ' => 'Ⲍ', 'ⲏ' => 'Ⲏ', 'ⲑ' => 'Ⲑ', 'ⲓ' => 'Ⲓ', 'ⲕ' => 'Ⲕ', 'ⲗ' => 'Ⲗ', 'ⲙ' => 'Ⲙ', 'ⲛ' => 'Ⲛ', 'ⲝ' => 'Ⲝ', 'ⲟ' => 'Ⲟ', 'ⲡ' => 'Ⲡ', 'ⲣ' => 'Ⲣ', 'ⲥ' => 'Ⲥ', 'ⲧ' => 'Ⲧ', 'ⲩ' => 'Ⲩ', 'ⲫ' => 'Ⲫ', 'ⲭ' => 'Ⲭ', 'ⲯ' => 'Ⲯ', 'ⲱ' => 'Ⲱ', 'ⲳ' => 'Ⲳ', 'ⲵ' => 'Ⲵ', 'ⲷ' => 'Ⲷ', 'ⲹ' => 'Ⲹ', 'ⲻ' => 'Ⲻ', 'ⲽ' => 'Ⲽ', 'ⲿ' => 'Ⲿ', 'ⳁ' => 'Ⳁ', 'ⳃ' => 'Ⳃ', 'ⳅ' => 'Ⳅ', 'ⳇ' => 'Ⳇ', 'ⳉ' => 'Ⳉ', 'ⳋ' => 'Ⳋ', 'ⳍ' => 'Ⳍ', 'ⳏ' => 'Ⳏ', 'ⳑ' => 'Ⳑ', 'ⳓ' => 'Ⳓ', 'ⳕ' => 'Ⳕ', 'ⳗ' => 'Ⳗ', 'ⳙ' => 'Ⳙ', 'ⳛ' => 'Ⳛ', 'ⳝ' => 'Ⳝ', 'ⳟ' => 'Ⳟ', 'ⳡ' => 'Ⳡ', 'ⳣ' => 'Ⳣ', 'ⳬ' => 'Ⳬ', 'ⳮ' => 'Ⳮ', 'ⳳ' => 'Ⳳ', 'ⴀ' => 'Ⴀ', 'ⴁ' => 'Ⴁ', 'ⴂ' => 'Ⴂ', 'ⴃ' => 'Ⴃ', 'ⴄ' => 'Ⴄ', 'ⴅ' => 'Ⴅ', 'ⴆ' => 'Ⴆ', 'ⴇ' => 'Ⴇ', 'ⴈ' => 'Ⴈ', 'ⴉ' => 'Ⴉ', 'ⴊ' => 'Ⴊ', 'ⴋ' => 'Ⴋ', 'ⴌ' => 'Ⴌ', 'ⴍ' => 'Ⴍ', 'ⴎ' => 'Ⴎ', 'ⴏ' => 'Ⴏ', 'ⴐ' => 'Ⴐ', 'ⴑ' => 'Ⴑ', 'ⴒ' => 'Ⴒ', 'ⴓ' => 'Ⴓ', 'ⴔ' => 'Ⴔ', 'ⴕ' => 'Ⴕ', 'ⴖ' => 'Ⴖ', 'ⴗ' => 'Ⴗ', 'ⴘ' => 'Ⴘ', 'ⴙ' => 'Ⴙ', 'ⴚ' => 'Ⴚ', 'ⴛ' => 'Ⴛ', 'ⴜ' => 'Ⴜ', 'ⴝ' => 'Ⴝ', 'ⴞ' => 'Ⴞ', 'ⴟ' => 'Ⴟ', 'ⴠ' => 'Ⴠ', 'ⴡ' => 'Ⴡ', 'ⴢ' => 'Ⴢ', 'ⴣ' => 'Ⴣ', 'ⴤ' => 'Ⴤ', 'ⴥ' => 'Ⴥ', 'ⴧ' => 'Ⴧ', 'ⴭ' => 'Ⴭ', 'ꙁ' => 'Ꙁ', 'ꙃ' => 'Ꙃ', 'ꙅ' => 'Ꙅ', 'ꙇ' => 'Ꙇ', 'ꙉ' => 'Ꙉ', 'ꙋ' => 'Ꙋ', 'ꙍ' => 'Ꙍ', 'ꙏ' => 'Ꙏ', 'ꙑ' => 'Ꙑ', 'ꙓ' => 'Ꙓ', 'ꙕ' => 'Ꙕ', 'ꙗ' => 'Ꙗ', 'ꙙ' => 'Ꙙ', 'ꙛ' => 'Ꙛ', 'ꙝ' => 'Ꙝ', 'ꙟ' => 'Ꙟ', 'ꙡ' => 'Ꙡ', 'ꙣ' => 'Ꙣ', 'ꙥ' => 'Ꙥ', 'ꙧ' => 'Ꙧ', 'ꙩ' => 'Ꙩ', 'ꙫ' => 'Ꙫ', 'ꙭ' => 'Ꙭ', 'ꚁ' => 'Ꚁ', 'ꚃ' => 'Ꚃ', 'ꚅ' => 'Ꚅ', 'ꚇ' => 'Ꚇ', 'ꚉ' => 'Ꚉ', 'ꚋ' => 'Ꚋ', 'ꚍ' => 'Ꚍ', 'ꚏ' => 'Ꚏ', 'ꚑ' => 'Ꚑ', 'ꚓ' => 'Ꚓ', 'ꚕ' => 'Ꚕ', 'ꚗ' => 'Ꚗ', 'ꚙ' => 'Ꚙ', 'ꚛ' => 'Ꚛ', 'ꜣ' => 'Ꜣ', 'ꜥ' => 'Ꜥ', 'ꜧ' => 'Ꜧ', 'ꜩ' => 'Ꜩ', 'ꜫ' => 'Ꜫ', 'ꜭ' => 'Ꜭ', 'ꜯ' => 'Ꜯ', 'ꜳ' => 'Ꜳ', 'ꜵ' => 'Ꜵ', 'ꜷ' => 'Ꜷ', 'ꜹ' => 'Ꜹ', 'ꜻ' => 'Ꜻ', 'ꜽ' => 'Ꜽ', 'ꜿ' => 'Ꜿ', 'ꝁ' => 'Ꝁ', 'ꝃ' => 'Ꝃ', 'ꝅ' => 'Ꝅ', 'ꝇ' => 'Ꝇ', 'ꝉ' => 'Ꝉ', 'ꝋ' => 'Ꝋ', 'ꝍ' => 'Ꝍ', 'ꝏ' => 'Ꝏ', 'ꝑ' => 'Ꝑ', 'ꝓ' => 'Ꝓ', 'ꝕ' => 'Ꝕ', 'ꝗ' => 'Ꝗ', 'ꝙ' => 'Ꝙ', 'ꝛ' => 'Ꝛ', 'ꝝ' => 'Ꝝ', 'ꝟ' => 'Ꝟ', 'ꝡ' => 'Ꝡ', 'ꝣ' => 'Ꝣ', 'ꝥ' => 'Ꝥ', 'ꝧ' => 'Ꝧ', 'ꝩ' => 'Ꝩ', 'ꝫ' => 'Ꝫ', 'ꝭ' => 'Ꝭ', 'ꝯ' => 'Ꝯ', 'ꝺ' => 'Ꝺ', 'ꝼ' => 'Ꝼ', 'ꝿ' => 'Ꝿ', 'ꞁ' => 'Ꞁ', 'ꞃ' => 'Ꞃ', 'ꞅ' => 'Ꞅ', 'ꞇ' => 'Ꞇ', 'ꞌ' => 'Ꞌ', 'ꞑ' => 'Ꞑ', 'ꞓ' => 'Ꞓ', 'ꞔ' => 'Ꞔ', 'ꞗ' => 'Ꞗ', 'ꞙ' => 'Ꞙ', 'ꞛ' => 'Ꞛ', 'ꞝ' => 'Ꞝ', 'ꞟ' => 'Ꞟ', 'ꞡ' => 'Ꞡ', 'ꞣ' => 'Ꞣ', 'ꞥ' => 'Ꞥ', 'ꞧ' => 'Ꞧ', 'ꞩ' => 'Ꞩ', 'ꞵ' => 'Ꞵ', 'ꞷ' => 'Ꞷ', 'ꞹ' => 'Ꞹ', 'ꞻ' => 'Ꞻ', 'ꞽ' => 'Ꞽ', 'ꞿ' => 'Ꞿ', 'ꟃ' => 'Ꟃ', 'ꟈ' => 'Ꟈ', 'ꟊ' => 'Ꟊ', 'ꟶ' => 'Ꟶ', 'ꭓ' => 'Ꭓ', 'ꭰ' => 'Ꭰ', 'ꭱ' => 'Ꭱ', 'ꭲ' => 'Ꭲ', 'ꭳ' => 'Ꭳ', 'ꭴ' => 'Ꭴ', 'ꭵ' => 'Ꭵ', 'ꭶ' => 'Ꭶ', 'ꭷ' => 'Ꭷ', 'ꭸ' => 'Ꭸ', 'ꭹ' => 'Ꭹ', 'ꭺ' => 'Ꭺ', 'ꭻ' => 'Ꭻ', 'ꭼ' => 'Ꭼ', 'ꭽ' => 'Ꭽ', 'ꭾ' => 'Ꭾ', 'ꭿ' => 'Ꭿ', 'ꮀ' => 'Ꮀ', 'ꮁ' => 'Ꮁ', 'ꮂ' => 'Ꮂ', 'ꮃ' => 'Ꮃ', 'ꮄ' => 'Ꮄ', 'ꮅ' => 'Ꮅ', 'ꮆ' => 'Ꮆ', 'ꮇ' => 'Ꮇ', 'ꮈ' => 'Ꮈ', 'ꮉ' => 'Ꮉ', 'ꮊ' => 'Ꮊ', 'ꮋ' => 'Ꮋ', 'ꮌ' => 'Ꮌ', 'ꮍ' => 'Ꮍ', 'ꮎ' => 'Ꮎ', 'ꮏ' => 'Ꮏ', 'ꮐ' => 'Ꮐ', 'ꮑ' => 'Ꮑ', 'ꮒ' => 'Ꮒ', 'ꮓ' => 'Ꮓ', 'ꮔ' => 'Ꮔ', 'ꮕ' => 'Ꮕ', 'ꮖ' => 'Ꮖ', 'ꮗ' => 'Ꮗ', 'ꮘ' => 'Ꮘ', 'ꮙ' => 'Ꮙ', 'ꮚ' => 'Ꮚ', 'ꮛ' => 'Ꮛ', 'ꮜ' => 'Ꮜ', 'ꮝ' => 'Ꮝ', 'ꮞ' => 'Ꮞ', 'ꮟ' => 'Ꮟ', 'ꮠ' => 'Ꮠ', 'ꮡ' => 'Ꮡ', 'ꮢ' => 'Ꮢ', 'ꮣ' => 'Ꮣ', 'ꮤ' => 'Ꮤ', 'ꮥ' => 'Ꮥ', 'ꮦ' => 'Ꮦ', 'ꮧ' => 'Ꮧ', 'ꮨ' => 'Ꮨ', 'ꮩ' => 'Ꮩ', 'ꮪ' => 'Ꮪ', 'ꮫ' => 'Ꮫ', 'ꮬ' => 'Ꮬ', 'ꮭ' => 'Ꮭ', 'ꮮ' => 'Ꮮ', 'ꮯ' => 'Ꮯ', 'ꮰ' => 'Ꮰ', 'ꮱ' => 'Ꮱ', 'ꮲ' => 'Ꮲ', 'ꮳ' => 'Ꮳ', 'ꮴ' => 'Ꮴ', 'ꮵ' => 'Ꮵ', 'ꮶ' => 'Ꮶ', 'ꮷ' => 'Ꮷ', 'ꮸ' => 'Ꮸ', 'ꮹ' => 'Ꮹ', 'ꮺ' => 'Ꮺ', 'ꮻ' => 'Ꮻ', 'ꮼ' => 'Ꮼ', 'ꮽ' => 'Ꮽ', 'ꮾ' => 'Ꮾ', 'ꮿ' => 'Ꮿ', 'a' => 'A', 'b' => 'B', 'c' => 'C', 'd' => 'D', 'e' => 'E', 'f' => 'F', 'g' => 'G', 'h' => 'H', 'i' => 'I', 'j' => 'J', 'k' => 'K', 'l' => 'L', 'm' => 'M', 'n' => 'N', 'o' => 'O', 'p' => 'P', 'q' => 'Q', 'r' => 'R', 's' => 'S', 't' => 'T', 'u' => 'U', 'v' => 'V', 'w' => 'W', 'x' => 'X', 'y' => 'Y', 'z' => 'Z', '𐐨' => '𐐀', '𐐩' => '𐐁', '𐐪' => '𐐂', '𐐫' => '𐐃', '𐐬' => '𐐄', '𐐭' => '𐐅', '𐐮' => '𐐆', '𐐯' => '𐐇', '𐐰' => '𐐈', '𐐱' => '𐐉', '𐐲' => '𐐊', '𐐳' => '𐐋', '𐐴' => '𐐌', '𐐵' => '𐐍', '𐐶' => '𐐎', '𐐷' => '𐐏', '𐐸' => '𐐐', '𐐹' => '𐐑', '𐐺' => '𐐒', '𐐻' => '𐐓', '𐐼' => '𐐔', '𐐽' => '𐐕', '𐐾' => '𐐖', '𐐿' => '𐐗', '𐑀' => '𐐘', '𐑁' => '𐐙', '𐑂' => '𐐚', '𐑃' => '𐐛', '𐑄' => '𐐜', '𐑅' => '𐐝', '𐑆' => '𐐞', '𐑇' => '𐐟', '𐑈' => '𐐠', '𐑉' => '𐐡', '𐑊' => '𐐢', '𐑋' => '𐐣', '𐑌' => '𐐤', '𐑍' => '𐐥', '𐑎' => '𐐦', '𐑏' => '𐐧', '𐓘' => '𐒰', '𐓙' => '𐒱', '𐓚' => '𐒲', '𐓛' => '𐒳', '𐓜' => '𐒴', '𐓝' => '𐒵', '𐓞' => '𐒶', '𐓟' => '𐒷', '𐓠' => '𐒸', '𐓡' => '𐒹', '𐓢' => '𐒺', '𐓣' => '𐒻', '𐓤' => '𐒼', '𐓥' => '𐒽', '𐓦' => '𐒾', '𐓧' => '𐒿', '𐓨' => '𐓀', '𐓩' => '𐓁', '𐓪' => '𐓂', '𐓫' => '𐓃', '𐓬' => '𐓄', '𐓭' => '𐓅', '𐓮' => '𐓆', '𐓯' => '𐓇', '𐓰' => '𐓈', '𐓱' => '𐓉', '𐓲' => '𐓊', '𐓳' => '𐓋', '𐓴' => '𐓌', '𐓵' => '𐓍', '𐓶' => '𐓎', '𐓷' => '𐓏', '𐓸' => '𐓐', '𐓹' => '𐓑', '𐓺' => '𐓒', '𐓻' => '𐓓', '𐳀' => '𐲀', '𐳁' => '𐲁', '𐳂' => '𐲂', '𐳃' => '𐲃', '𐳄' => '𐲄', '𐳅' => '𐲅', '𐳆' => '𐲆', '𐳇' => '𐲇', '𐳈' => '𐲈', '𐳉' => '𐲉', '𐳊' => '𐲊', '𐳋' => '𐲋', '𐳌' => '𐲌', '𐳍' => '𐲍', '𐳎' => '𐲎', '𐳏' => '𐲏', '𐳐' => '𐲐', '𐳑' => '𐲑', '𐳒' => '𐲒', '𐳓' => '𐲓', '𐳔' => '𐲔', '𐳕' => '𐲕', '𐳖' => '𐲖', '𐳗' => '𐲗', '𐳘' => '𐲘', '𐳙' => '𐲙', '𐳚' => '𐲚', '𐳛' => '𐲛', '𐳜' => '𐲜', '𐳝' => '𐲝', '𐳞' => '𐲞', '𐳟' => '𐲟', '𐳠' => '𐲠', '𐳡' => '𐲡', '𐳢' => '𐲢', '𐳣' => '𐲣', '𐳤' => '𐲤', '𐳥' => '𐲥', '𐳦' => '𐲦', '𐳧' => '𐲧', '𐳨' => '𐲨', '𐳩' => '𐲩', '𐳪' => '𐲪', '𐳫' => '𐲫', '𐳬' => '𐲬', '𐳭' => '𐲭', '𐳮' => '𐲮', '𐳯' => '𐲯', '𐳰' => '𐲰', '𐳱' => '𐲱', '𐳲' => '𐲲', '𑣀' => '𑢠', '𑣁' => '𑢡', '𑣂' => '𑢢', '𑣃' => '𑢣', '𑣄' => '𑢤', '𑣅' => '𑢥', '𑣆' => '𑢦', '𑣇' => '𑢧', '𑣈' => '𑢨', '𑣉' => '𑢩', '𑣊' => '𑢪', '𑣋' => '𑢫', '𑣌' => '𑢬', '𑣍' => '𑢭', '𑣎' => '𑢮', '𑣏' => '𑢯', '𑣐' => '𑢰', '𑣑' => '𑢱', '𑣒' => '𑢲', '𑣓' => '𑢳', '𑣔' => '𑢴', '𑣕' => '𑢵', '𑣖' => '𑢶', '𑣗' => '𑢷', '𑣘' => '𑢸', '𑣙' => '𑢹', '𑣚' => '𑢺', '𑣛' => '𑢻', '𑣜' => '𑢼', '𑣝' => '𑢽', '𑣞' => '𑢾', '𑣟' => '𑢿', '𖹠' => '𖹀', '𖹡' => '𖹁', '𖹢' => '𖹂', '𖹣' => '𖹃', '𖹤' => '𖹄', '𖹥' => '𖹅', '𖹦' => '𖹆', '𖹧' => '𖹇', '𖹨' => '𖹈', '𖹩' => '𖹉', '𖹪' => '𖹊', '𖹫' => '𖹋', '𖹬' => '𖹌', '𖹭' => '𖹍', '𖹮' => '𖹎', '𖹯' => '𖹏', '𖹰' => '𖹐', '𖹱' => '𖹑', '𖹲' => '𖹒', '𖹳' => '𖹓', '𖹴' => '𖹔', '𖹵' => '𖹕', '𖹶' => '𖹖', '𖹷' => '𖹗', '𖹸' => '𖹘', '𖹹' => '𖹙', '𖹺' => '𖹚', '𖹻' => '𖹛', '𖹼' => '𖹜', '𖹽' => '𖹝', '𖹾' => '𖹞', '𖹿' => '𖹟', '𞤢' => '𞤀', '𞤣' => '𞤁', '𞤤' => '𞤂', '𞤥' => '𞤃', '𞤦' => '𞤄', '𞤧' => '𞤅', '𞤨' => '𞤆', '𞤩' => '𞤇', '𞤪' => '𞤈', '𞤫' => '𞤉', '𞤬' => '𞤊', '𞤭' => '𞤋', '𞤮' => '𞤌', '𞤯' => '𞤍', '𞤰' => '𞤎', '𞤱' => '𞤏', '𞤲' => '𞤐', '𞤳' => '𞤑', '𞤴' => '𞤒', '𞤵' => '𞤓', '𞤶' => '𞤔', '𞤷' => '𞤕', '𞤸' => '𞤖', '𞤹' => '𞤗', '𞤺' => '𞤘', '𞤻' => '𞤙', '𞤼' => '𞤚', '𞤽' => '𞤛', '𞤾' => '𞤜', '𞤿' => '𞤝', '𞥀' => '𞤞', '𞥁' => '𞤟', '𞥂' => '𞤠', '𞥃' => '𞤡', 'ß' => 'SS', 'ff' => 'FF', 'fi' => 'FI', 'fl' => 'FL', 'ffi' => 'FFI', 'ffl' => 'FFL', 'ſt' => 'ST', 'st' => 'ST', 'և' => 'ԵՒ', 'ﬓ' => 'ՄՆ', 'ﬔ' => 'ՄԵ', 'ﬕ' => 'ՄԻ', 'ﬖ' => 'ՎՆ', 'ﬗ' => 'ՄԽ', 'ʼn' => 'ʼN', 'ΐ' => 'Ϊ́', 'ΰ' => 'Ϋ́', 'ǰ' => 'J̌', 'ẖ' => 'H̱', 'ẗ' => 'T̈', 'ẘ' => 'W̊', 'ẙ' => 'Y̊', 'ẚ' => 'Aʾ', 'ὐ' => 'Υ̓', 'ὒ' => 'Υ̓̀', 'ὔ' => 'Υ̓́', 'ὖ' => 'Υ̓͂', 'ᾶ' => 'Α͂', 'ῆ' => 'Η͂', 'ῒ' => 'Ϊ̀', 'ΐ' => 'Ϊ́', 'ῖ' => 'Ι͂', 'ῗ' => 'Ϊ͂', 'ῢ' => 'Ϋ̀', 'ΰ' => 'Ϋ́', 'ῤ' => 'Ρ̓', 'ῦ' => 'Υ͂', 'ῧ' => 'Ϋ͂', 'ῶ' => 'Ω͂', 'ᾈ' => 'ἈΙ', 'ᾉ' => 'ἉΙ', 'ᾊ' => 'ἊΙ', 'ᾋ' => 'ἋΙ', 'ᾌ' => 'ἌΙ', 'ᾍ' => 'ἍΙ', 'ᾎ' => 'ἎΙ', 'ᾏ' => 'ἏΙ', 'ᾘ' => 'ἨΙ', 'ᾙ' => 'ἩΙ', 'ᾚ' => 'ἪΙ', 'ᾛ' => 'ἫΙ', 'ᾜ' => 'ἬΙ', 'ᾝ' => 'ἭΙ', 'ᾞ' => 'ἮΙ', 'ᾟ' => 'ἯΙ', 'ᾨ' => 'ὨΙ', 'ᾩ' => 'ὩΙ', 'ᾪ' => 'ὪΙ', 'ᾫ' => 'ὫΙ', 'ᾬ' => 'ὬΙ', 'ᾭ' => 'ὭΙ', 'ᾮ' => 'ὮΙ', 'ᾯ' => 'ὯΙ', 'ᾼ' => 'ΑΙ', 'ῌ' => 'ΗΙ', 'ῼ' => 'ΩΙ', 'ᾲ' => 'ᾺΙ', 'ᾴ' => 'ΆΙ', 'ῂ' => 'ῊΙ', 'ῄ' => 'ΉΙ', 'ῲ' => 'ῺΙ', 'ῴ' => 'ΏΙ', 'ᾷ' => 'Α͂Ι', 'ῇ' => 'Η͂Ι', 'ῷ' => 'Ω͂Ι'); diff --git a/vendor-bundle/symfony/polyfill-mbstring/bootstrap.php b/vendor-bundle/symfony/polyfill-mbstring/bootstrap.php new file mode 100644 index 000000000..56eb11ebd --- /dev/null +++ b/vendor-bundle/symfony/polyfill-mbstring/bootstrap.php @@ -0,0 +1,258 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Phabel\Symfony\Polyfill\Mbstring as p; +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__ . '/bootstrap80.php'; +} +if (!\function_exists('mb_convert_encoding')) { + function mb_convert_encoding($string, $to_encoding, $from_encoding = null) + { + return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); + } +} +if (!\function_exists('mb_decode_mimeheader')) { + function mb_decode_mimeheader($string) + { + return p\Mbstring::mb_decode_mimeheader($string); + } +} +if (!\function_exists('mb_encode_mimeheader')) { + function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) + { + return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); + } +} +if (!\function_exists('mb_decode_numericentity')) { + function mb_decode_numericentity($string, $map, $encoding = null) + { + return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); + } +} +if (!\function_exists('mb_encode_numericentity')) { + function mb_encode_numericentity($string, $map, $encoding = null, $hex = \false) + { + return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); + } +} +if (!\function_exists('mb_convert_case')) { + function mb_convert_case($string, $mode, $encoding = null) + { + return p\Mbstring::mb_convert_case($string, $mode, $encoding); + } +} +if (!\function_exists('mb_internal_encoding')) { + function mb_internal_encoding($encoding = null) + { + return p\Mbstring::mb_internal_encoding($encoding); + } +} +if (!\function_exists('mb_language')) { + function mb_language($language = null) + { + return p\Mbstring::mb_language($language); + } +} +if (!\function_exists('mb_list_encodings')) { + function mb_list_encodings() + { + return p\Mbstring::mb_list_encodings(); + } +} +if (!\function_exists('mb_encoding_aliases')) { + function mb_encoding_aliases($encoding) + { + return p\Mbstring::mb_encoding_aliases($encoding); + } +} +if (!\function_exists('mb_check_encoding')) { + function mb_check_encoding($value = null, $encoding = null) + { + return p\Mbstring::mb_check_encoding($value, $encoding); + } +} +if (!\function_exists('mb_detect_encoding')) { + function mb_detect_encoding($string, $encodings = null, $strict = \false) + { + return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); + } +} +if (!\function_exists('mb_detect_order')) { + function mb_detect_order($encoding = null) + { + return p\Mbstring::mb_detect_order($encoding); + } +} +if (!\function_exists('mb_parse_str')) { + function mb_parse_str($string, &$result = []) + { + \parse_str($string, $result); + return (bool) $result; + } +} +if (!\function_exists('mb_strlen')) { + function mb_strlen($string, $encoding = null) + { + return p\Mbstring::mb_strlen($string, $encoding); + } +} +if (!\function_exists('mb_strpos')) { + function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) + { + return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); + } +} +if (!\function_exists('mb_strtolower')) { + function mb_strtolower($string, $encoding = null) + { + return p\Mbstring::mb_strtolower($string, $encoding); + } +} +if (!\function_exists('mb_strtoupper')) { + function mb_strtoupper($string, $encoding = null) + { + return p\Mbstring::mb_strtoupper($string, $encoding); + } +} +if (!\function_exists('mb_substitute_character')) { + function mb_substitute_character($substitute_character = null) + { + return p\Mbstring::mb_substitute_character($substitute_character); + } +} +if (!\function_exists('mb_substr')) { + function mb_substr($string, $start, $length = 2147483647, $encoding = null) + { + return p\Mbstring::mb_substr($string, $start, $length, $encoding); + } +} +if (!\function_exists('mb_stripos')) { + function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) + { + return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); + } +} +if (!\function_exists('mb_stristr')) { + function mb_stristr($haystack, $needle, $before_needle = \false, $encoding = null) + { + return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); + } +} +if (!\function_exists('mb_strrchr')) { + function mb_strrchr($haystack, $needle, $before_needle = \false, $encoding = null) + { + return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); + } +} +if (!\function_exists('mb_strrichr')) { + function mb_strrichr($haystack, $needle, $before_needle = \false, $encoding = null) + { + return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); + } +} +if (!\function_exists('mb_strripos')) { + function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) + { + return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); + } +} +if (!\function_exists('mb_strrpos')) { + function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) + { + return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); + } +} +if (!\function_exists('mb_strstr')) { + function mb_strstr($haystack, $needle, $before_needle = \false, $encoding = null) + { + return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); + } +} +if (!\function_exists('mb_get_info')) { + function mb_get_info($type = 'all') + { + return p\Mbstring::mb_get_info($type); + } +} +if (!\function_exists('mb_http_output')) { + function mb_http_output($encoding = null) + { + return p\Mbstring::mb_http_output($encoding); + } +} +if (!\function_exists('mb_strwidth')) { + function mb_strwidth($string, $encoding = null) + { + return p\Mbstring::mb_strwidth($string, $encoding); + } +} +if (!\function_exists('mb_substr_count')) { + function mb_substr_count($haystack, $needle, $encoding = null) + { + return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); + } +} +if (!\function_exists('mb_output_handler')) { + function mb_output_handler($string, $status) + { + return p\Mbstring::mb_output_handler($string, $status); + } +} +if (!\function_exists('mb_http_input')) { + function mb_http_input($type = null) + { + return p\Mbstring::mb_http_input($type); + } +} +if (!\function_exists('mb_convert_variables')) { + function mb_convert_variables($to_encoding, $from_encoding, &...$vars) + { + return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); + } +} +if (!\function_exists('mb_ord')) { + function mb_ord($string, $encoding = null) + { + return p\Mbstring::mb_ord($string, $encoding); + } +} +if (!\function_exists('mb_chr')) { + function mb_chr($codepoint, $encoding = null) + { + return p\Mbstring::mb_chr($codepoint, $encoding); + } +} +if (!\function_exists('mb_scrub')) { + function mb_scrub($string, $encoding = null) + { + $encoding = null === $encoding ? \mb_internal_encoding() : $encoding; + return \mb_convert_encoding($string, $encoding, $encoding); + } +} +if (!\function_exists('mb_str_split')) { + function mb_str_split($string, $length = 1, $encoding = null) + { + return p\Mbstring::mb_str_split($string, $length, $encoding); + } +} +if (\extension_loaded('mbstring')) { + return; +} +if (!\defined('MB_CASE_UPPER')) { + \define('MB_CASE_UPPER', 0); +} +if (!\defined('MB_CASE_LOWER')) { + \define('MB_CASE_LOWER', 1); +} +if (!\defined('MB_CASE_TITLE')) { + \define('MB_CASE_TITLE', 2); +} diff --git a/vendor-bundle/symfony/polyfill-mbstring/bootstrap80.php b/vendor-bundle/symfony/polyfill-mbstring/bootstrap80.php new file mode 100644 index 000000000..8b86fd672 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-mbstring/bootstrap80.php @@ -0,0 +1,1458 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Phabel\Symfony\Polyfill\Mbstring as p; +if (!\function_exists('mb_convert_encoding')) { + function mb_convert_encoding($string, $to_encoding, $from_encoding = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + if (!\is_array($string)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type array|string|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $string = (string) $string; + } + } + } + if (!\is_null($to_encoding)) { + if (!\is_string($to_encoding)) { + if (!(\is_string($to_encoding) || \is_object($to_encoding) && \method_exists($to_encoding, '__toString') || (\is_bool($to_encoding) || \is_numeric($to_encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($to_encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($to_encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $to_encoding = (string) $to_encoding; + } + } + } + if (!(\is_null($from_encoding) || \is_null($from_encoding))) { + if (!\is_string($from_encoding)) { + if (!(\is_string($from_encoding) || \is_object($from_encoding) && \method_exists($from_encoding, '__toString') || (\is_bool($from_encoding) || \is_numeric($from_encoding)))) { + if (!\is_array($from_encoding)) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($from_encoding) must be of type ?array|string|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($from_encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $from_encoding = (string) $from_encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_convert_encoding(isset($string) ? $string : '', (string) $to_encoding, $from_encoding); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|array|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_decode_mimeheader')) { + function mb_decode_mimeheader($string) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + $phabelReturn = p\Mbstring::mb_decode_mimeheader((string) $string); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_encode_mimeheader')) { + function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($charset)) { + if (!\is_string($charset)) { + if (!(\is_string($charset) || \is_object($charset) && \method_exists($charset, '__toString') || (\is_bool($charset) || \is_numeric($charset)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($charset) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($charset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $charset = (string) $charset; + } + } + } + if (!\is_null($transfer_encoding)) { + if (!\is_string($transfer_encoding)) { + if (!(\is_string($transfer_encoding) || \is_object($transfer_encoding) && \method_exists($transfer_encoding, '__toString') || (\is_bool($transfer_encoding) || \is_numeric($transfer_encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($transfer_encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($transfer_encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $transfer_encoding = (string) $transfer_encoding; + } + } + } + if (!\is_null($newline)) { + if (!\is_string($newline)) { + if (!(\is_string($newline) || \is_object($newline) && \method_exists($newline, '__toString') || (\is_bool($newline) || \is_numeric($newline)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($newline) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($newline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $newline = (string) $newline; + } + } + } + if (!\is_null($indent)) { + if (!\is_int($indent)) { + if (!(\is_bool($indent) || \is_numeric($indent))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($indent) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($indent) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $indent = (int) $indent; + } + } + } + $phabelReturn = p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_decode_numericentity')) { + function mb_decode_numericentity($string, array $map, $encoding = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_encode_numericentity')) { + function mb_encode_numericentity($string, array $map, $encoding = null, $hex = \false) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + if (!\is_null($hex)) { + if (!\is_bool($hex)) { + if (!(\is_bool($hex) || \is_numeric($hex) || \is_string($hex))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($hex) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($hex) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $hex = (bool) $hex; + } + } + } + $phabelReturn = p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_convert_case')) { + function mb_convert_case($string, $mode, $encoding = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($mode)) { + if (!\is_int($mode)) { + if (!(\is_bool($mode) || \is_numeric($mode))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($mode) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($mode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $mode = (int) $mode; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_internal_encoding')) { + function mb_internal_encoding($encoding = null) + { + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_internal_encoding($encoding); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_language')) { + function mb_language($language = null) + { + if (!\is_null($language)) { + if (!\is_string($language)) { + if (!(\is_string($language) || \is_object($language) && \method_exists($language, '__toString') || (\is_bool($language) || \is_numeric($language)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($language) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($language) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $language = (string) $language; + } + } + } + $phabelReturn = p\Mbstring::mb_language($language); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_list_encodings')) { + function mb_list_encodings() + { + $phabelReturn = p\Mbstring::mb_list_encodings(); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} +if (!\function_exists('mb_encoding_aliases')) { + function mb_encoding_aliases($encoding) + { + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_encoding_aliases((string) $encoding); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} +if (!\function_exists('mb_check_encoding')) { + function mb_check_encoding($value = null, $encoding = null) + { + if (!(\is_null($value) || \is_null($value))) { + if (!\is_string($value)) { + if (!(\is_string($value) || \is_object($value) && \method_exists($value, '__toString') || (\is_bool($value) || \is_numeric($value)))) { + if (!\is_array($value)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($value) must be of type ?array|string|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($value) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $value = (string) $value; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_check_encoding($value, $encoding); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_detect_encoding')) { + function mb_detect_encoding($string, $encodings = null, $strict = \false) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!(\is_null($encodings) || \is_null($encodings))) { + if (!\is_string($encodings)) { + if (!(\is_string($encodings) || \is_object($encodings) && \method_exists($encodings, '__toString') || (\is_bool($encodings) || \is_numeric($encodings)))) { + if (!\is_array($encodings)) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($encodings) must be of type ?array|string|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encodings) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $encodings = (string) $encodings; + } + } + } + if (!\is_null($strict)) { + if (!\is_bool($strict)) { + if (!(\is_bool($strict) || \is_numeric($strict) || \is_string($strict))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($strict) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($strict) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $strict = (bool) $strict; + } + } + } + $phabelReturn = p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_detect_order')) { + function mb_detect_order($encoding = null) + { + if (!(\is_null($encoding) || \is_null($encoding))) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + if (!\is_array($encoding)) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($encoding) must be of type ?array|string|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_detect_order($encoding); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_parse_str')) { + function mb_parse_str($string, &$result = []) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + \parse_str((string) $string, $result); + $phabelReturn = (bool) $result; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_strlen')) { + function mb_strlen($string, $encoding = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_strlen((string) $string, $encoding); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_strpos')) { + function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($offset)) { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); + if (!$phabelReturn instanceof false) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_strtolower')) { + function mb_strtolower($string, $encoding = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_strtolower((string) $string, $encoding); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_strtoupper')) { + function mb_strtoupper($string, $encoding = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_strtoupper((string) $string, $encoding); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_substitute_character')) { + function mb_substitute_character($substitute_character = null) + { + if (!(\is_null($substitute_character) || \is_null($substitute_character))) { + if (!\is_int($substitute_character)) { + if (!(\is_bool($substitute_character) || \is_numeric($substitute_character))) { + if (!\is_string($substitute_character)) { + if (!(\is_string($substitute_character) || \is_object($substitute_character) && \method_exists($substitute_character, '__toString') || (\is_bool($substitute_character) || \is_numeric($substitute_character)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($substitute_character) must be of type ?string|int|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($substitute_character) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $substitute_character = (string) $substitute_character; + } + } + } else { + $substitute_character = (int) $substitute_character; + } + } + } + $phabelReturn = p\Mbstring::mb_substitute_character($substitute_character); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|int|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_substr')) { + function mb_substr($string, $start, $length = null, $encoding = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($start)) { + if (!\is_int($start)) { + if (!(\is_bool($start) || \is_numeric($start))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($start) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($start) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $start = (int) $start; + } + } + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_stripos')) { + function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($offset)) { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); + if (!$phabelReturn instanceof false) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_stristr')) { + function mb_stristr($haystack, $needle, $before_needle = \false, $encoding = null) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($before_needle)) { + if (!\is_bool($before_needle)) { + if (!(\is_bool($before_needle) || \is_numeric($before_needle) || \is_string($before_needle))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($before_needle) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($before_needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $before_needle = (bool) $before_needle; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_strrchr')) { + function mb_strrchr($haystack, $needle, $before_needle = \false, $encoding = null) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($before_needle)) { + if (!\is_bool($before_needle)) { + if (!(\is_bool($before_needle) || \is_numeric($before_needle) || \is_string($before_needle))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($before_needle) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($before_needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $before_needle = (bool) $before_needle; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_strrichr')) { + function mb_strrichr($haystack, $needle, $before_needle = \false, $encoding = null) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($before_needle)) { + if (!\is_bool($before_needle)) { + if (!(\is_bool($before_needle) || \is_numeric($before_needle) || \is_string($before_needle))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($before_needle) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($before_needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $before_needle = (bool) $before_needle; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_strripos')) { + function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($offset)) { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); + if (!$phabelReturn instanceof false) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_strrpos')) { + function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($offset)) { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); + if (!$phabelReturn instanceof false) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_strstr')) { + function mb_strstr($haystack, $needle, $before_needle = \false, $encoding = null) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($before_needle)) { + if (!\is_bool($before_needle)) { + if (!(\is_bool($before_needle) || \is_numeric($before_needle) || \is_string($before_needle))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($before_needle) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($before_needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $before_needle = (bool) $before_needle; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_get_info')) { + function mb_get_info($type = 'all') + { + if (!\is_null($type)) { + if (!\is_string($type)) { + if (!(\is_string($type) || \is_object($type) && \method_exists($type, '__toString') || (\is_bool($type) || \is_numeric($type)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($type) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (string) $type; + } + } + } + $phabelReturn = p\Mbstring::mb_get_info((string) $type); + if (!$phabelReturn instanceof false) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|array|string|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_http_output')) { + function mb_http_output($encoding = null) + { + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_http_output($encoding); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string|bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_strwidth')) { + function mb_strwidth($string, $encoding = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_strwidth((string) $string, $encoding); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_substr_count')) { + function mb_substr_count($haystack, $needle, $encoding = null) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_output_handler')) { + function mb_output_handler($string, $status) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($status)) { + if (!\is_int($status)) { + if (!(\is_bool($status) || \is_numeric($status))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($status) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($status) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $status = (int) $status; + } + } + } + $phabelReturn = p\Mbstring::mb_output_handler((string) $string, (int) $status); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_http_input')) { + function mb_http_input($type = null) + { + if (!\is_null($type)) { + if (!\is_string($type)) { + if (!(\is_string($type) || \is_object($type) && \method_exists($type, '__toString') || (\is_bool($type) || \is_numeric($type)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($type) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (string) $type; + } + } + } + $phabelReturn = p\Mbstring::mb_http_input($type); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|array|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_convert_variables')) { + function mb_convert_variables($to_encoding, $from_encoding, mixed &$var, mixed &...$vars) + { + if (!\is_null($to_encoding)) { + if (!\is_string($to_encoding)) { + if (!(\is_string($to_encoding) || \is_object($to_encoding) && \method_exists($to_encoding, '__toString') || (\is_bool($to_encoding) || \is_numeric($to_encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($to_encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($to_encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $to_encoding = (string) $to_encoding; + } + } + } + if (!\is_null($from_encoding)) { + if (!\is_string($from_encoding)) { + if (!(\is_string($from_encoding) || \is_object($from_encoding) && \method_exists($from_encoding, '__toString') || (\is_bool($from_encoding) || \is_numeric($from_encoding)))) { + if (!\is_array($from_encoding)) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($from_encoding) must be of type array|string|null, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($from_encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + } else { + $from_encoding = (string) $from_encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_convert_variables((string) $to_encoding, isset($from_encoding) ? $from_encoding : '', $var, ...$vars); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_ord')) { + function mb_ord($string, $encoding = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_ord((string) $string, $encoding); + if (!$phabelReturn instanceof false) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_chr')) { + function mb_chr($codepoint, $encoding = null) + { + if (!\is_null($codepoint)) { + if (!\is_int($codepoint)) { + if (!(\is_bool($codepoint) || \is_numeric($codepoint))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($codepoint) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($codepoint) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $codepoint = (int) $codepoint; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_chr((int) $codepoint, $encoding); + if (!$phabelReturn instanceof false) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type false|string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_scrub')) { + function mb_scrub($string, $encoding = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $encoding = isset($encoding) ? $encoding : \mb_internal_encoding(); + $phabelReturn = \mb_convert_encoding((string) $string, $encoding, $encoding); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('mb_str_split')) { + function mb_str_split($string, $length = 1, $encoding = null) + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + } + if (!\is_null($encoding)) { + if (!\is_string($encoding)) { + if (!(\is_string($encoding) || \is_object($encoding) && \method_exists($encoding, '__toString') || (\is_bool($encoding) || \is_numeric($encoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($encoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($encoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $encoding = (string) $encoding; + } + } + } + $phabelReturn = p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} +if (\extension_loaded('mbstring')) { + return; +} +if (!\defined('MB_CASE_UPPER')) { + \define('MB_CASE_UPPER', 0); +} +if (!\defined('MB_CASE_LOWER')) { + \define('MB_CASE_LOWER', 1); +} +if (!\defined('MB_CASE_TITLE')) { + \define('MB_CASE_TITLE', 2); +} diff --git a/vendor-bundle/symfony/polyfill-php72/Php72.php b/vendor-bundle/symfony/polyfill-php72/Php72.php new file mode 100644 index 000000000..e953b8cf9 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-php72/Php72.php @@ -0,0 +1,176 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Polyfill\Php72; + +/** + * @author Nicolas Grekas + * @author Dariusz Rumiński + * + * @internal + */ +final class Php72 +{ + private static $hashMask; + public static function utf8_encode($s) + { + $s .= $s; + $len = \strlen($s); + for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) { + switch (\true) { + case $s[$i] < "\x80": + $s[$j] = $s[$i]; + break; + case $s[$i] < "\xc0": + $s[$j] = "\xc2"; + $s[++$j] = $s[$i]; + break; + default: + $s[$j] = "\xc3"; + $s[++$j] = \chr(\ord($s[$i]) - 64); + break; + } + } + return \substr($s, 0, $j); + } + public static function utf8_decode($s) + { + $s = (string) $s; + $len = \strlen($s); + for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) { + switch ($s[$i] & "\xf0") { + case "\xc0": + case "\xd0": + $c = \ord($s[$i] & "\x1f") << 6 | \ord($s[++$i] & "?"); + $s[$j] = $c < 256 ? \chr($c) : '?'; + break; + case "\xf0": + ++$i; + // no break + case "\xe0": + $s[$j] = '?'; + $i += 2; + break; + default: + $s[$j] = $s[$i]; + } + } + return \substr($s, 0, $j); + } + public static function php_os_family() + { + if ('\\' === \DIRECTORY_SEPARATOR) { + return 'Windows'; + } + $map = ['Darwin' => 'Darwin', 'DragonFly' => 'BSD', 'FreeBSD' => 'BSD', 'NetBSD' => 'BSD', 'OpenBSD' => 'BSD', 'Linux' => 'Linux', 'SunOS' => 'Solaris']; + return isset($map[\PHP_OS]) ? $map[\PHP_OS] : 'Unknown'; + } + public static function spl_object_id($object) + { + if (null === self::$hashMask) { + self::initHashMask(); + } + if (null === ($hash = \spl_object_hash($object))) { + return; + } + // On 32-bit systems, PHP_INT_SIZE is 4, + return self::$hashMask ^ \hexdec(\substr($hash, 16 - (\PHP_INT_SIZE * 2 - 1), \PHP_INT_SIZE * 2 - 1)); + } + public static function sapi_windows_vt100_support($stream, $enable = null) + { + if (!\is_resource($stream)) { + \trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, ' . \gettype($stream) . ' given', \E_USER_WARNING); + return \false; + } + $meta = \stream_get_meta_data($stream); + if ('STDIO' !== $meta['stream_type']) { + \trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', \E_USER_WARNING); + return \false; + } + // We cannot actually disable vt100 support if it is set + if (\false === $enable || !self::stream_isatty($stream)) { + return \false; + } + // The native function does not apply to stdin + $meta = \array_map('strtolower', $meta); + $stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri']; + return !$stdin && (\false !== \getenv('ANSICON') || 'ON' === \getenv('ConEmuANSI') || 'xterm' === \getenv('TERM') || 'Hyper' === \getenv('TERM_PROGRAM')); + } + public static function stream_isatty($stream) + { + if (!\is_resource($stream)) { + \trigger_error('stream_isatty() expects parameter 1 to be resource, ' . \gettype($stream) . ' given', \E_USER_WARNING); + return \false; + } + if ('\\' === \DIRECTORY_SEPARATOR) { + $stat = @\fstat($stream); + // Check if formatted mode is S_IFCHR + return $stat ? 020000 === ($stat['mode'] & 0170000) : \false; + } + return \function_exists('posix_isatty') && @\posix_isatty($stream); + } + private static function initHashMask() + { + $obj = (object) []; + self::$hashMask = -1; + // check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below + $obFuncs = ['ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush']; + foreach (\debug_backtrace(\PHP_VERSION_ID >= 50400 ? \DEBUG_BACKTRACE_IGNORE_ARGS : \false) as $frame) { + if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) { + $frame['line'] = 0; + break; + } + } + if (!empty($frame['line'])) { + \ob_start(); + \debug_zval_dump($obj); + self::$hashMask = (int) \substr(\ob_get_clean(), 17); + } + self::$hashMask ^= \hexdec(\substr(\spl_object_hash($obj), 16 - (\PHP_INT_SIZE * 2 - 1), \PHP_INT_SIZE * 2 - 1)); + } + public static function mb_chr($code, $encoding = null) + { + if (0x80 > ($code %= 0x200000)) { + $s = \chr($code); + } elseif (0x800 > $code) { + $s = \chr(0xc0 | $code >> 6) . \chr(0x80 | $code & 0x3f); + } elseif (0x10000 > $code) { + $s = \chr(0xe0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f); + } else { + $s = \chr(0xf0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3f) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f); + } + if ('UTF-8' !== ($encoding = isset($encoding) ? $encoding : \mb_internal_encoding())) { + $s = \mb_convert_encoding($s, $encoding, 'UTF-8'); + } + return $s; + } + public static function mb_ord($s, $encoding = null) + { + if (null === $encoding) { + $s = \mb_convert_encoding($s, 'UTF-8'); + } elseif ('UTF-8' !== $encoding) { + $s = \mb_convert_encoding($s, 'UTF-8', $encoding); + } + if (1 === \strlen($s)) { + return \ord($s); + } + $code = ($s = \unpack('C*', \substr($s, 0, 4))) ? $s[1] : 0; + if (0xf0 <= $code) { + return ($code - 0xf0 << 18) + ($s[2] - 0x80 << 12) + ($s[3] - 0x80 << 6) + $s[4] - 0x80; + } + if (0xe0 <= $code) { + return ($code - 0xe0 << 12) + ($s[2] - 0x80 << 6) + $s[3] - 0x80; + } + if (0xc0 <= $code) { + return ($code - 0xc0 << 6) + $s[2] - 0x80; + } + return $code; + } +} diff --git a/vendor-bundle/symfony/polyfill-php72/bootstrap.php b/vendor-bundle/symfony/polyfill-php72/bootstrap.php new file mode 100644 index 000000000..1e7ae6e72 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-php72/bootstrap.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Phabel\Symfony\Polyfill\Php72 as p; +if (\PHP_VERSION_ID >= 70200) { + return; +} +if (!\defined('PHP_FLOAT_DIG')) { + \define('PHP_FLOAT_DIG', 15); +} +if (!\defined('PHP_FLOAT_EPSILON')) { + \define('PHP_FLOAT_EPSILON', 2.2204460492503E-16); +} +if (!\defined('PHP_FLOAT_MIN')) { + \define('PHP_FLOAT_MIN', 2.2250738585072E-308); +} +if (!\defined('PHP_FLOAT_MAX')) { + \define('PHP_FLOAT_MAX', 1.7976931348623157E+308); +} +if (!\defined('PHP_OS_FAMILY')) { + \define('PHP_OS_FAMILY', p\Php72::php_os_family()); +} +if ('\\' === \DIRECTORY_SEPARATOR && !\function_exists('sapi_windows_vt100_support')) { + function sapi_windows_vt100_support($stream, $enable = null) + { + return p\Php72::sapi_windows_vt100_support($stream, $enable); + } +} +if (!\function_exists('stream_isatty')) { + function stream_isatty($stream) + { + return p\Php72::stream_isatty($stream); + } +} +if (!\function_exists('utf8_encode')) { + function utf8_encode($string) + { + return p\Php72::utf8_encode($string); + } +} +if (!\function_exists('utf8_decode')) { + function utf8_decode($string) + { + return p\Php72::utf8_decode($string); + } +} +if (!\function_exists('spl_object_id')) { + function spl_object_id($object) + { + return p\Php72::spl_object_id($object); + } +} +if (!\function_exists('mb_ord')) { + function mb_ord($string, $encoding = null) + { + return p\Php72::mb_ord($string, $encoding); + } +} +if (!\function_exists('mb_chr')) { + function mb_chr($codepoint, $encoding = null) + { + return p\Php72::mb_chr($codepoint, $encoding); + } +} +if (!\function_exists('mb_scrub')) { + function mb_scrub($string, $encoding = null) + { + $encoding = null === $encoding ? \mb_internal_encoding() : $encoding; + return \mb_convert_encoding($string, $encoding, $encoding); + } +} diff --git a/vendor-bundle/symfony/polyfill-php73/Php73.php b/vendor-bundle/symfony/polyfill-php73/Php73.php new file mode 100644 index 000000000..9e1ae7ccf --- /dev/null +++ b/vendor-bundle/symfony/polyfill-php73/Php73.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Polyfill\Php73; + +/** + * @author Gabriel Caruso + * @author Ion Bazan + * + * @internal + */ +final class Php73 +{ + public static $startAt = 1533462603; + /** + * @param bool $asNum + * + * @return array|float|int + */ + public static function hrtime($asNum = \false) + { + $ns = \microtime(\false); + $s = \substr($ns, 11) - self::$startAt; + $ns = 1000000000.0 * (float) $ns; + if ($asNum) { + $ns += $s * 1000000000.0; + return \PHP_INT_SIZE === 4 ? $ns : (int) $ns; + } + return [$s, (int) $ns]; + } +} diff --git a/vendor-bundle/symfony/polyfill-php73/Resources/stubs/JsonException.php b/vendor-bundle/symfony/polyfill-php73/Resources/stubs/JsonException.php new file mode 100644 index 000000000..8154d503e --- /dev/null +++ b/vendor-bundle/symfony/polyfill-php73/Resources/stubs/JsonException.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +class JsonException extends \Exception +{ +} +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +\class_alias('Phabel\\JsonException', 'JsonException', \false); diff --git a/vendor-bundle/symfony/polyfill-php73/bootstrap.php b/vendor-bundle/symfony/polyfill-php73/bootstrap.php new file mode 100644 index 000000000..11f58a0e0 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-php73/bootstrap.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Phabel\Symfony\Polyfill\Php73 as p; +if (\PHP_VERSION_ID >= 70300) { + return; +} +if (!\function_exists('is_countable')) { + function is_countable($value) + { + return \is_array($value) || $value instanceof \Countable || $value instanceof \ResourceBundle || $value instanceof SimpleXmlElement; + } +} +if (!\function_exists('hrtime')) { + require_once __DIR__ . '/Php73.php'; + p\Php73::$startAt = (int) \microtime(\true); + function hrtime($as_number = \false) + { + return p\Php73::hrtime($as_number); + } +} +if (!\function_exists('array_key_first')) { + function array_key_first(array $array) + { + foreach ($array as $key => $value) { + return $key; + } + } +} +if (!\function_exists('array_key_last')) { + function array_key_last(array $array) + { + return \key(\array_slice($array, -1, 1, \true)); + } +} diff --git a/vendor-bundle/symfony/polyfill-php74/Php74.php b/vendor-bundle/symfony/polyfill-php74/Php74.php new file mode 100644 index 000000000..32af50c79 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-php74/Php74.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Polyfill\Php74; + +/** + * @author Ion Bazan + * + * @internal + */ +final class Php74 +{ + public static function get_mangled_object_vars($obj) + { + if (!\is_object($obj)) { + \trigger_error('get_mangled_object_vars() expects parameter 1 to be object, ' . \gettype($obj) . ' given', \E_USER_WARNING); + return null; + } + if ($obj instanceof \ArrayIterator || $obj instanceof \ArrayObject) { + $reflector = new \ReflectionClass($obj instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject'); + $flags = $reflector->getMethod('getFlags')->invoke($obj); + $reflector = $reflector->getMethod('setFlags'); + $reflector->invoke($obj, $flags & \ArrayObject::STD_PROP_LIST ? 0 : \ArrayObject::STD_PROP_LIST); + $arr = (array) $obj; + $reflector->invoke($obj, $flags); + } else { + $arr = (array) $obj; + } + return \array_combine(\array_keys($arr), \array_values($arr)); + } + public static function mb_str_split($string, $split_length = 1, $encoding = null) + { + if (null !== $string && !\is_scalar($string) && !(\is_object($string) && \method_exists($string, '__toString'))) { + \trigger_error('mb_str_split() expects parameter 1 to be string, ' . \gettype($string) . ' given', \E_USER_WARNING); + return null; + } + if (1 > ($split_length = (int) $split_length)) { + \trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING); + return \false; + } + if (null === $encoding) { + $encoding = \mb_internal_encoding(); + } + if ('UTF-8' === $encoding || \in_array(\strtoupper($encoding), ['UTF-8', 'UTF8'], \true)) { + return \preg_split("/(.{{$split_length}})/u", $string, null, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); + } + $result = []; + $length = \mb_strlen($string, $encoding); + for ($i = 0; $i < $length; $i += $split_length) { + $result[] = \mb_substr($string, $i, $split_length, $encoding); + } + return $result; + } + public static function password_algos() + { + $algos = []; + if (\defined('PASSWORD_BCRYPT')) { + $algos[] = \PASSWORD_BCRYPT; + } + if (\defined('PASSWORD_ARGON2I')) { + $algos[] = \PASSWORD_ARGON2I; + } + if (\defined('PASSWORD_ARGON2ID')) { + $algos[] = \PASSWORD_ARGON2ID; + } + return $algos; + } +} diff --git a/vendor-bundle/symfony/polyfill-php74/bootstrap.php b/vendor-bundle/symfony/polyfill-php74/bootstrap.php new file mode 100644 index 000000000..fc2ca06d1 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-php74/bootstrap.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Phabel\Symfony\Polyfill\Php74 as p; +if (\PHP_VERSION_ID >= 70400) { + return; +} +if (!\function_exists('get_mangled_object_vars')) { + function get_mangled_object_vars($object) + { + return p\Php74::get_mangled_object_vars($object); + } +} +if (!\function_exists('mb_str_split') && \function_exists('mb_substr')) { + function mb_str_split($string, $length = 1, $encoding = null) + { + return p\Php74::mb_str_split($string, $length, $encoding); + } +} +if (!\function_exists('password_algos')) { + function password_algos() + { + return p\Php74::password_algos(); + } +} diff --git a/vendor-bundle/symfony/polyfill-php80/Php80.php b/vendor-bundle/symfony/polyfill-php80/Php80.php new file mode 100644 index 000000000..a1e7edaeb --- /dev/null +++ b/vendor-bundle/symfony/polyfill-php80/Php80.php @@ -0,0 +1,349 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Polyfill\Php80; + +/** + * @author Ion Bazan + * @author Nico Oelgart + * @author Nicolas Grekas + * + * @internal + */ +final class Php80 +{ + public static function fdiv($dividend, $divisor) + { + if (!\is_float($dividend)) { + if (!(\is_bool($dividend) || \is_numeric($dividend))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($dividend) must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($dividend) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $dividend = (double) $dividend; + } + } + if (!\is_float($divisor)) { + if (!(\is_bool($divisor) || \is_numeric($divisor))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($divisor) must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($divisor) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $divisor = (double) $divisor; + } + } + $phabelReturn = @($dividend / $divisor); + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } + public static function get_debug_type($value) + { + switch (\true) { + case null === $value: + $phabelReturn = 'null'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \is_bool($value): + $phabelReturn = 'bool'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \is_string($value): + $phabelReturn = 'string'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \is_array($value): + $phabelReturn = 'array'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \is_int($value): + $phabelReturn = 'int'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \is_float($value): + $phabelReturn = 'float'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \is_object($value): + break; + case $value instanceof \__PHP_Incomplete_Class: + $phabelReturn = '__PHP_Incomplete_Class'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + default: + if (null === ($type = @\get_resource_type($value))) { + $phabelReturn = 'unknown'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if ('Unknown' === $type) { + $type = 'closed'; + } + $phabelReturn = "resource ({$type})"; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $class = \get_class($value); + if (\false === \strpos($class, '@')) { + $phabelReturn = $class; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = ((\get_parent_class($class) ?: \key(\class_implements($class))) ?: 'class') . '@anonymous'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public static function get_resource_id($res) + { + if (!\is_resource($res) && null === @\get_resource_type($res)) { + throw new \TypeError(\sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', \get_debug_type($res))); + } + $phabelReturn = (int) $res; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + public static function preg_last_error_msg() + { + switch (\preg_last_error()) { + case \PREG_INTERNAL_ERROR: + $phabelReturn = 'Internal error'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \PREG_BAD_UTF8_ERROR: + $phabelReturn = 'Malformed UTF-8 characters, possibly incorrectly encoded'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \PREG_BAD_UTF8_OFFSET_ERROR: + $phabelReturn = 'The offset did not correspond to the beginning of a valid UTF-8 code point'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \PREG_BACKTRACK_LIMIT_ERROR: + $phabelReturn = 'Backtrack limit exhausted'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \PREG_RECURSION_LIMIT_ERROR: + $phabelReturn = 'Recursion limit exhausted'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \PREG_JIT_STACKLIMIT_ERROR: + $phabelReturn = 'JIT stack limit exhausted'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + case \PREG_NO_ERROR: + $phabelReturn = 'No error'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + default: + $phabelReturn = 'Unknown error'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + public static function str_contains($haystack, $needle) + { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + $phabelReturn = '' === $needle || \false !== \strpos($haystack, $needle); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public static function str_starts_with($haystack, $needle) + { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + $phabelReturn = 0 === \strncmp($haystack, $needle, \strlen($needle)); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public static function str_ends_with($haystack, $needle) + { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + $phabelReturn = '' === $needle || '' !== $haystack && 0 === \substr_compare($haystack, $needle, -\strlen($needle)); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/polyfill-php80/Resources/stubs/Attribute.php b/vendor-bundle/symfony/polyfill-php80/Resources/stubs/Attribute.php new file mode 100644 index 000000000..889564fbb --- /dev/null +++ b/vendor-bundle/symfony/polyfill-php80/Resources/stubs/Attribute.php @@ -0,0 +1,30 @@ +flags = $flags; + } +} +\class_alias('Phabel\\Attribute', 'Attribute', \false); diff --git a/vendor-bundle/symfony/polyfill-php80/Resources/stubs/Stringable.php b/vendor-bundle/symfony/polyfill-php80/Resources/stubs/Stringable.php new file mode 100644 index 000000000..145f31f92 --- /dev/null +++ b/vendor-bundle/symfony/polyfill-php80/Resources/stubs/Stringable.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Phabel\Symfony\Polyfill\Php80 as p; +if (\PHP_VERSION_ID >= 80000) { + return; +} +if (!\defined('FILTER_VALIDATE_BOOL') && \defined('FILTER_VALIDATE_BOOLEAN')) { + \define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN); +} +if (!\function_exists('fdiv')) { + function fdiv($num1, $num2) + { + if (!\is_float($num1)) { + if (!(\is_bool($num1) || \is_numeric($num1))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($num1) must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($num1) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $num1 = (double) $num1; + } + } + if (!\is_float($num2)) { + if (!(\is_bool($num2) || \is_numeric($num2))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($num2) must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($num2) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $num2 = (double) $num2; + } + } + $phabelReturn = p\Php80::fdiv($num1, $num2); + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('preg_last_error_msg')) { + function preg_last_error_msg() + { + $phabelReturn = p\Php80::preg_last_error_msg(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('str_contains')) { + function str_contains($haystack, $needle) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + $phabelReturn = p\Php80::str_contains(isset($haystack) ? $haystack : '', isset($needle) ? $needle : ''); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('str_starts_with')) { + function str_starts_with($haystack, $needle) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + $phabelReturn = p\Php80::str_starts_with(isset($haystack) ? $haystack : '', isset($needle) ? $needle : ''); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('str_ends_with')) { + function str_ends_with($haystack, $needle) + { + if (!\is_null($haystack)) { + if (!\is_string($haystack)) { + if (!(\is_string($haystack) || \is_object($haystack) && \method_exists($haystack, '__toString') || (\is_bool($haystack) || \is_numeric($haystack)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($haystack) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haystack) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haystack = (string) $haystack; + } + } + } + if (!\is_null($needle)) { + if (!\is_string($needle)) { + if (!(\is_string($needle) || \is_object($needle) && \method_exists($needle, '__toString') || (\is_bool($needle) || \is_numeric($needle)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($needle) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($needle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $needle = (string) $needle; + } + } + } + $phabelReturn = p\Php80::str_ends_with(isset($haystack) ? $haystack : '', isset($needle) ? $needle : ''); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('get_debug_type')) { + function get_debug_type($value) + { + $phabelReturn = p\Php80::get_debug_type($value); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} +if (!\function_exists('get_resource_id')) { + function get_resource_id($resource) + { + $phabelReturn = p\Php80::get_resource_id($resource); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/process/Exception/ExceptionInterface.php b/vendor-bundle/symfony/process/Exception/ExceptionInterface.php new file mode 100644 index 000000000..ff38fb17b --- /dev/null +++ b/vendor-bundle/symfony/process/Exception/ExceptionInterface.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process\Exception; + +/** + * Marker Interface for the Process Component. + * + * @author Johannes M. Schmitt + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/vendor-bundle/symfony/process/Exception/InvalidArgumentException.php b/vendor-bundle/symfony/process/Exception/InvalidArgumentException.php new file mode 100644 index 000000000..a21909a4e --- /dev/null +++ b/vendor-bundle/symfony/process/Exception/InvalidArgumentException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process\Exception; + +/** + * InvalidArgumentException for the Process Component. + * + * @author Romain Neutron + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor-bundle/symfony/process/Exception/LogicException.php b/vendor-bundle/symfony/process/Exception/LogicException.php new file mode 100644 index 000000000..f37ce0bca --- /dev/null +++ b/vendor-bundle/symfony/process/Exception/LogicException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process\Exception; + +/** + * LogicException for the Process Component. + * + * @author Romain Neutron + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/vendor-bundle/symfony/process/Exception/ProcessFailedException.php b/vendor-bundle/symfony/process/Exception/ProcessFailedException.php new file mode 100644 index 000000000..c1a847c8e --- /dev/null +++ b/vendor-bundle/symfony/process/Exception/ProcessFailedException.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process\Exception; + +use Phabel\Symfony\Component\Process\Process; +/** + * Exception for failed processes. + * + * @author Johannes M. Schmitt + */ +class ProcessFailedException extends RuntimeException +{ + private $process; + public function __construct(Process $process) + { + if ($process->isSuccessful()) { + throw new InvalidArgumentException('Expected a failed process, but the given process was successful.'); + } + $error = \sprintf('The command "%s" failed. + +Exit Code: %s(%s) + +Working directory: %s', $process->getCommandLine(), $process->getExitCode(), $process->getExitCodeText(), $process->getWorkingDirectory()); + if (!$process->isOutputDisabled()) { + $error .= \sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", $process->getOutput(), $process->getErrorOutput()); + } + parent::__construct($error); + $this->process = $process; + } + public function getProcess() + { + return $this->process; + } +} diff --git a/vendor-bundle/symfony/process/Exception/ProcessSignaledException.php b/vendor-bundle/symfony/process/Exception/ProcessSignaledException.php new file mode 100644 index 000000000..16d177dab --- /dev/null +++ b/vendor-bundle/symfony/process/Exception/ProcessSignaledException.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process\Exception; + +use Phabel\Symfony\Component\Process\Process; +/** + * Exception that is thrown when a process has been signaled. + * + * @author Sullivan Senechal + */ +final class ProcessSignaledException extends RuntimeException +{ + private $process; + public function __construct(Process $process) + { + $this->process = $process; + parent::__construct(\sprintf('The process has been signaled with signal "%s".', $process->getTermSignal())); + } + public function getProcess() + { + $phabelReturn = $this->process; + if (!$phabelReturn instanceof Process) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type Process, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function getSignal() + { + $phabelReturn = $this->getProcess()->getTermSignal(); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/process/Exception/ProcessTimedOutException.php b/vendor-bundle/symfony/process/Exception/ProcessTimedOutException.php new file mode 100644 index 000000000..34119d59e --- /dev/null +++ b/vendor-bundle/symfony/process/Exception/ProcessTimedOutException.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process\Exception; + +use Phabel\Symfony\Component\Process\Process; +/** + * Exception that is thrown when a process times out. + * + * @author Johannes M. Schmitt + */ +class ProcessTimedOutException extends RuntimeException +{ + const TYPE_GENERAL = 1; + const TYPE_IDLE = 2; + private $process; + private $timeoutType; + public function __construct(Process $process, $timeoutType) + { + if (!\is_int($timeoutType)) { + if (!(\is_bool($timeoutType) || \is_numeric($timeoutType))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($timeoutType) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeoutType) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $timeoutType = (int) $timeoutType; + } + } + $this->process = $process; + $this->timeoutType = $timeoutType; + parent::__construct(\sprintf('The process "%s" exceeded the timeout of %s seconds.', $process->getCommandLine(), $this->getExceededTimeout())); + } + public function getProcess() + { + return $this->process; + } + public function isGeneralTimeout() + { + return self::TYPE_GENERAL === $this->timeoutType; + } + public function isIdleTimeout() + { + return self::TYPE_IDLE === $this->timeoutType; + } + public function getExceededTimeout() + { + switch ($this->timeoutType) { + case self::TYPE_GENERAL: + return $this->process->getTimeout(); + case self::TYPE_IDLE: + return $this->process->getIdleTimeout(); + default: + throw new \LogicException(\sprintf('Unknown timeout type "%d".', $this->timeoutType)); + } + } +} diff --git a/vendor-bundle/symfony/process/Exception/RuntimeException.php b/vendor-bundle/symfony/process/Exception/RuntimeException.php new file mode 100644 index 000000000..2b4348c20 --- /dev/null +++ b/vendor-bundle/symfony/process/Exception/RuntimeException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process\Exception; + +/** + * RuntimeException for the Process Component. + * + * @author Johannes M. Schmitt + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor-bundle/symfony/process/ExecutableFinder.php b/vendor-bundle/symfony/process/ExecutableFinder.php new file mode 100644 index 000000000..d8287152f --- /dev/null +++ b/vendor-bundle/symfony/process/ExecutableFinder.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process; + +/** + * Generic executable finder. + * + * @author Fabien Potencier + * @author Johannes M. Schmitt + */ +class ExecutableFinder +{ + private $suffixes = ['.exe', '.bat', '.cmd', '.com']; + /** + * Replaces default suffixes of executable. + */ + public function setSuffixes(array $suffixes) + { + $this->suffixes = $suffixes; + } + /** + * Adds new possible suffix to check for executable. + */ + public function addSuffix($suffix) + { + if (!\is_string($suffix)) { + if (!(\is_string($suffix) || \is_object($suffix) && \method_exists($suffix, '__toString') || (\is_bool($suffix) || \is_numeric($suffix)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($suffix) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($suffix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $suffix = (string) $suffix; + } + } + $this->suffixes[] = $suffix; + } + /** + * Finds an executable by name. + * + * @param string $name The executable name (without the extension) + * @param string|null $default The default to return if no executable is found + * @param array $extraDirs Additional dirs to check into + * + * @return string|null The executable path or default value + */ + public function find($name, $default = null, array $extraDirs = []) + { + if (!\is_string($name)) { + if (!(\is_string($name) || \is_object($name) && \method_exists($name, '__toString') || (\is_bool($name) || \is_numeric($name)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($name) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($name) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $name = (string) $name; + } + } + if (!\is_null($default)) { + if (!\is_string($default)) { + if (!(\is_string($default) || \is_object($default) && \method_exists($default, '__toString') || (\is_bool($default) || \is_numeric($default)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($default) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($default) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $default = (string) $default; + } + } + } + if (\ini_get('open_basedir')) { + $searchPath = \array_merge(\explode(\PATH_SEPARATOR, \ini_get('open_basedir')), $extraDirs); + $dirs = []; + foreach ($searchPath as $path) { + // Silencing against https://bugs.php.net/69240 + if (@\is_dir($path)) { + $dirs[] = $path; + } else { + if (\basename($path) == $name && @\is_executable($path)) { + return $path; + } + } + } + } else { + $dirs = \array_merge(\explode(\PATH_SEPARATOR, \getenv('PATH') ?: \getenv('Path')), $extraDirs); + } + $suffixes = ['']; + if ('\\' === \DIRECTORY_SEPARATOR) { + $pathExt = \getenv('PATHEXT'); + $suffixes = \array_merge($pathExt ? \explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes); + } + foreach ($suffixes as $suffix) { + foreach ($dirs as $dir) { + if (@\is_file($file = $dir . \DIRECTORY_SEPARATOR . $name . $suffix) && ('\\' === \DIRECTORY_SEPARATOR || @\is_executable($file))) { + return $file; + } + } + } + return $default; + } +} diff --git a/vendor-bundle/symfony/process/InputStream.php b/vendor-bundle/symfony/process/InputStream.php new file mode 100644 index 000000000..771401f38 --- /dev/null +++ b/vendor-bundle/symfony/process/InputStream.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process; + +use Phabel\Symfony\Component\Process\Exception\RuntimeException; +/** + * Provides a way to continuously write to the input of a Process until the InputStream is closed. + * + * @author Nicolas Grekas + */ +class InputStream implements \IteratorAggregate +{ + /** @var callable|null */ + private $onEmpty = null; + private $input = []; + private $open = \true; + /** + * Sets a callback that is called when the write buffer becomes empty. + */ + public function onEmpty(callable $onEmpty = null) + { + $this->onEmpty = $onEmpty; + } + /** + * Appends an input to the write buffer. + * + * @param resource|string|int|float|bool|\Traversable|null $input The input to append as scalar, + * stream resource or \Traversable + */ + public function write($input) + { + if (null === $input) { + return; + } + if ($this->isClosed()) { + throw new RuntimeException(\sprintf('"%s" is closed.', static::class)); + } + $this->input[] = ProcessUtils::validateInput(__METHOD__, $input); + } + /** + * Closes the write buffer. + */ + public function close() + { + $this->open = \false; + } + /** + * Tells whether the write buffer is closed or not. + */ + public function isClosed() + { + return !$this->open; + } + /** + * @return \Traversable + */ + public function getIterator() + { + $this->open = \true; + while ($this->open || $this->input) { + if (!$this->input) { + (yield ''); + continue; + } + $current = \array_shift($this->input); + if ($current instanceof \Iterator) { + yield from $current; + } else { + (yield $current); + } + if (!$this->input && $this->open && null !== ($onEmpty = $this->onEmpty)) { + $this->write($onEmpty($this)); + } + } + } +} diff --git a/vendor-bundle/symfony/process/PhpExecutableFinder.php b/vendor-bundle/symfony/process/PhpExecutableFinder.php new file mode 100644 index 000000000..463d1f54b --- /dev/null +++ b/vendor-bundle/symfony/process/PhpExecutableFinder.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process; + +/** + * An executable finder specifically designed for the PHP executable. + * + * @author Fabien Potencier + * @author Johannes M. Schmitt + */ +class PhpExecutableFinder +{ + private $executableFinder; + public function __construct() + { + $this->executableFinder = new ExecutableFinder(); + } + /** + * Finds The PHP executable. + * + * @return string|false The PHP executable path or false if it cannot be found + */ + public function find($includeArgs = \true) + { + if (!\is_bool($includeArgs)) { + if (!(\is_bool($includeArgs) || \is_numeric($includeArgs) || \is_string($includeArgs))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($includeArgs) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($includeArgs) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $includeArgs = (bool) $includeArgs; + } + } + if ($php = \getenv('PHP_BINARY')) { + if (!\is_executable($php)) { + $command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v'; + if ($php = \strtok(\exec($command . ' ' . \escapeshellarg($php)), \PHP_EOL)) { + if (!\is_executable($php)) { + return \false; + } + } else { + return \false; + } + } + return $php; + } + $args = $this->findArguments(); + $args = $includeArgs && $args ? ' ' . \implode(' ', $args) : ''; + // PHP_BINARY return the current sapi executable + if (\PHP_BINARY && \in_array(\PHP_SAPI, ['cgi-fcgi', 'cli', 'cli-server', 'phpdbg'], \true)) { + return \PHP_BINARY . $args; + } + if ($php = \getenv('PHP_PATH')) { + if (!@\is_executable($php)) { + return \false; + } + return $php; + } + if ($php = \getenv('PHP_PEAR_PHP_BIN')) { + if (@\is_executable($php)) { + return $php; + } + } + if (@\is_executable($php = \PHP_BINDIR . ('\\' === \DIRECTORY_SEPARATOR ? '\\php.exe' : '/php'))) { + return $php; + } + $dirs = [\PHP_BINDIR]; + if ('\\' === \DIRECTORY_SEPARATOR) { + $dirs[] = 'C:\\xampp\\php\\'; + } + return $this->executableFinder->find('php', \false, $dirs); + } + /** + * Finds the PHP executable arguments. + * + * @return array The PHP executable arguments + */ + public function findArguments() + { + $arguments = []; + if ('phpdbg' === \PHP_SAPI) { + $arguments[] = '-qrr'; + } + return $arguments; + } +} diff --git a/vendor-bundle/symfony/process/PhpProcess.php b/vendor-bundle/symfony/process/PhpProcess.php new file mode 100644 index 000000000..b9061970f --- /dev/null +++ b/vendor-bundle/symfony/process/PhpProcess.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process; + +use Phabel\Symfony\Component\Process\Exception\LogicException; +use Phabel\Symfony\Component\Process\Exception\RuntimeException; +/** + * PhpProcess runs a PHP script in an independent process. + * + * $p = new PhpProcess(''); + * $p->run(); + * print $p->getOutput()."\n"; + * + * @author Fabien Potencier + */ +class PhpProcess extends Process +{ + /** + * @param string $script The PHP script to run (as a string) + * @param string|null $cwd The working directory or null to use the working dir of the current PHP process + * @param array|null $env The environment variables or null to use the same environment as the current PHP process + * @param int $timeout The timeout in seconds + * @param array|null $php Path to the PHP binary to use with any additional arguments + */ + public function __construct($script, $cwd = null, array $env = null, $timeout = 60, $php = null) + { + if (!(\is_array($php) || \is_null($php))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($php) must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($php) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + if (!\is_string($script)) { + if (!(\is_string($script) || \is_object($script) && \method_exists($script, '__toString') || (\is_bool($script) || \is_numeric($script)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($script) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($script) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $script = (string) $script; + } + } + if (!\is_null($cwd)) { + if (!\is_string($cwd)) { + if (!(\is_string($cwd) || \is_object($cwd) && \method_exists($cwd, '__toString') || (\is_bool($cwd) || \is_numeric($cwd)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($cwd) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cwd) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cwd = (string) $cwd; + } + } + } + if (!\is_int($timeout)) { + if (!(\is_bool($timeout) || \is_numeric($timeout))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($timeout) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeout) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $timeout = (int) $timeout; + } + } + if (null === $php) { + $executableFinder = new PhpExecutableFinder(); + $php = $executableFinder->find(\false); + $php = \false === $php ? null : \array_merge([$php], $executableFinder->findArguments()); + } + if ('phpdbg' === \PHP_SAPI) { + $file = \tempnam(\sys_get_temp_dir(), 'dbg'); + \file_put_contents($file, $script); + \register_shutdown_function('unlink', $file); + $php[] = $file; + $script = null; + } + parent::__construct($php, $cwd, $env, $script, $timeout); + } + /** + * {@inheritdoc} + */ + public static function fromShellCommandline($command, $cwd = null, array $env = null, $input = null, $timeout = 60) + { + if (!\is_string($command)) { + if (!(\is_string($command) || \is_object($command) && \method_exists($command, '__toString') || (\is_bool($command) || \is_numeric($command)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($command) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($command) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $command = (string) $command; + } + } + if (!\is_null($cwd)) { + if (!\is_string($cwd)) { + if (!(\is_string($cwd) || \is_object($cwd) && \method_exists($cwd, '__toString') || (\is_bool($cwd) || \is_numeric($cwd)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($cwd) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cwd) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cwd = (string) $cwd; + } + } + } + if (!\is_null($timeout)) { + if (!\is_float($timeout)) { + if (!(\is_bool($timeout) || \is_numeric($timeout))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($timeout) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeout) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $timeout = (double) $timeout; + } + } + } + throw new LogicException(\sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); + } + /** + * {@inheritdoc} + */ + public function start(callable $callback = null, array $env = []) + { + if (null === $this->getCommandLine()) { + throw new RuntimeException('Unable to find the PHP executable.'); + } + parent::start($callback, $env); + } +} diff --git a/vendor-bundle/symfony/process/Pipes/AbstractPipes.php b/vendor-bundle/symfony/process/Pipes/AbstractPipes.php new file mode 100644 index 000000000..5d579b2c0 --- /dev/null +++ b/vendor-bundle/symfony/process/Pipes/AbstractPipes.php @@ -0,0 +1,204 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process\Pipes; + +use Phabel\Symfony\Component\Process\Exception\InvalidArgumentException; +/** + * @author Romain Neutron + * + * @internal + */ +abstract class AbstractPipes implements PipesInterface +{ + public $pipes = []; + private $inputBuffer = ''; + private $input; + private $blocked = \true; + private $lastError; + /** + * @param resource|string|int|float|bool|\Iterator|null $input + */ + public function __construct($input) + { + if (\is_resource($input) || $input instanceof \Iterator) { + $this->input = $input; + } elseif (\is_string($input)) { + $this->inputBuffer = $input; + } else { + $this->inputBuffer = (string) $input; + } + } + /** + * {@inheritdoc} + */ + public function close() + { + foreach ($this->pipes as $pipe) { + \fclose($pipe); + } + $this->pipes = []; + } + /** + * Returns true if a system call has been interrupted. + */ + protected function hasSystemCallBeenInterrupted() + { + $lastError = $this->lastError; + $this->lastError = null; + $phabelReturn = null !== $lastError && \false !== \stripos($lastError, 'interrupted system call'); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + // stream_select returns false when the `select` system call is interrupted by an incoming signal + return $phabelReturn; + } + /** + * Unblocks streams. + */ + protected function unblock() + { + if (!$this->blocked) { + return; + } + foreach ($this->pipes as $pipe) { + \stream_set_blocking($pipe, 0); + } + if (\is_resource($this->input)) { + \stream_set_blocking($this->input, 0); + } + $this->blocked = \false; + } + /** + * Writes input to stdin. + * + * @throws InvalidArgumentException When an input iterator yields a non supported value + */ + protected function write() + { + if (!isset($this->pipes[0])) { + $phabelReturn = null; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $input = $this->input; + if ($input instanceof \Iterator) { + if (!$input->valid()) { + $input = null; + } elseif (\is_resource($input = $input->current())) { + \stream_set_blocking($input, 0); + } elseif (!isset($this->inputBuffer[0])) { + if (!\is_string($input)) { + if (!\is_scalar($input)) { + throw new InvalidArgumentException(\sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', \get_debug_type($this->input), \get_debug_type($input))); + } + $input = (string) $input; + } + $this->inputBuffer = $input; + $this->input->next(); + $input = null; + } else { + $input = null; + } + } + $r = $e = []; + $w = [$this->pipes[0]]; + // let's have a look if something changed in streams + if (\false === @\stream_select($r, $w, $e, 0, 0)) { + $phabelReturn = null; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + foreach ($w as $stdin) { + if (isset($this->inputBuffer[0])) { + $written = \fwrite($stdin, $this->inputBuffer); + $this->inputBuffer = \substr($this->inputBuffer, $written); + if (isset($this->inputBuffer[0])) { + $phabelReturn = [$this->pipes[0]]; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + } + if ($input) { + for (;;) { + $data = \fread($input, self::CHUNK_SIZE); + if (!isset($data[0])) { + break; + } + $written = \fwrite($stdin, $data); + $data = \substr($data, $written); + if (isset($data[0])) { + $this->inputBuffer = $data; + $phabelReturn = [$this->pipes[0]]; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + } + if (\feof($input)) { + if ($this->input instanceof \Iterator) { + $this->input->next(); + } else { + $this->input = null; + } + } + } + } + // no input to read on resource, buffer is empty + if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) { + $this->input = null; + \fclose($this->pipes[0]); + unset($this->pipes[0]); + } elseif (!$w) { + $phabelReturn = [$this->pipes[0]]; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = null; + if (!(\is_array($phabelReturn) || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @internal + */ + public function handleError($type, $msg) + { + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + if (!\is_string($msg)) { + if (!(\is_string($msg) || \is_object($msg) && \method_exists($msg, '__toString') || (\is_bool($msg) || \is_numeric($msg)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($msg) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($msg) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $msg = (string) $msg; + } + } + $this->lastError = $msg; + } +} diff --git a/vendor-bundle/symfony/process/Pipes/PipesInterface.php b/vendor-bundle/symfony/process/Pipes/PipesInterface.php new file mode 100644 index 000000000..fb9d8fdf8 --- /dev/null +++ b/vendor-bundle/symfony/process/Pipes/PipesInterface.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process\Pipes; + +/** + * PipesInterface manages descriptors and pipes for the use of proc_open. + * + * @author Romain Neutron + * + * @internal + */ +interface PipesInterface +{ + const CHUNK_SIZE = 16384; + /** + * Returns an array of descriptors for the use of proc_open. + */ + public function getDescriptors(); + /** + * Returns an array of filenames indexed by their related stream in case these pipes use temporary files. + * + * @return string[] + */ + public function getFiles(); + /** + * Reads data in file handles and pipes. + * + * @param bool $blocking Whether to use blocking calls or not + * @param bool $close Whether to close pipes if they've reached EOF + * + * @return string[] An array of read data indexed by their fd + */ + public function readAndWrite($blocking, $close = \false); + /** + * Returns if the current state has open file handles or pipes. + */ + public function areOpen(); + /** + * Returns if pipes are able to read output. + */ + public function haveReadSupport(); + /** + * Closes file handles and pipes. + */ + public function close(); +} diff --git a/vendor-bundle/symfony/process/Pipes/UnixPipes.php b/vendor-bundle/symfony/process/Pipes/UnixPipes.php new file mode 100644 index 000000000..d96d50a53 --- /dev/null +++ b/vendor-bundle/symfony/process/Pipes/UnixPipes.php @@ -0,0 +1,212 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process\Pipes; + +use Phabel\Symfony\Component\Process\Process; +/** + * UnixPipes implementation uses unix pipes as handles. + * + * @author Romain Neutron + * + * @internal + */ +class UnixPipes extends AbstractPipes +{ + private $ttyMode; + private $ptyMode; + private $haveReadSupport; + public function __construct($ttyMode, $ptyMode, $input, $haveReadSupport) + { + if (!\is_null($ttyMode)) { + if (!\is_bool($ttyMode)) { + if (!(\is_bool($ttyMode) || \is_numeric($ttyMode) || \is_string($ttyMode))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($ttyMode) must be of type ?bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($ttyMode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $ttyMode = (bool) $ttyMode; + } + } + } + if (!\is_bool($ptyMode)) { + if (!(\is_bool($ptyMode) || \is_numeric($ptyMode) || \is_string($ptyMode))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($ptyMode) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($ptyMode) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $ptyMode = (bool) $ptyMode; + } + } + if (!\is_bool($haveReadSupport)) { + if (!(\is_bool($haveReadSupport) || \is_numeric($haveReadSupport) || \is_string($haveReadSupport))) { + throw new \TypeError(__METHOD__ . '(): Argument #4 ($haveReadSupport) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haveReadSupport) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haveReadSupport = (bool) $haveReadSupport; + } + } + $this->ttyMode = $ttyMode; + $this->ptyMode = $ptyMode; + $this->haveReadSupport = $haveReadSupport; + parent::__construct($input); + } + /** + * @return array + */ + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize ' . __CLASS__); + } + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__); + } + public function __destruct() + { + $this->close(); + } + /** + * {@inheritdoc} + */ + public function getDescriptors() + { + if (!$this->haveReadSupport) { + $nullstream = \fopen('/dev/null', 'c'); + $phabelReturn = [['pipe', 'r'], $nullstream, $nullstream]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->ttyMode) { + $phabelReturn = [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($this->ptyMode && Process::isPtySupported()) { + $phabelReturn = [['pty'], ['pty'], ['pty']]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = [ + ['pipe', 'r'], + ['pipe', 'w'], + // stdout + ['pipe', 'w'], + ]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function getFiles() + { + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function readAndWrite($blocking, $close = \false) + { + if (!\is_bool($blocking)) { + if (!(\is_bool($blocking) || \is_numeric($blocking) || \is_string($blocking))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($blocking) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($blocking) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $blocking = (bool) $blocking; + } + } + if (!\is_bool($close)) { + if (!(\is_bool($close) || \is_numeric($close) || \is_string($close))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($close) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($close) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $close = (bool) $close; + } + } + $this->unblock(); + $w = $this->write(); + $read = $e = []; + $r = $this->pipes; + unset($r[0]); + // let's have a look if something changed in streams + \set_error_handler([$this, 'handleError']); + if (($r || $w) && \false === \stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1000000.0 : 0)) { + \restore_error_handler(); + // if a system call has been interrupted, forget about it, let's try again + // otherwise, an error occurred, let's reset pipes + if (!$this->hasSystemCallBeenInterrupted()) { + $this->pipes = []; + } + $phabelReturn = $read; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + \restore_error_handler(); + foreach ($r as $pipe) { + // prior PHP 5.4 the array passed to stream_select is modified and + // lose key association, we have to find back the key + $read[$type = \array_search($pipe, $this->pipes, \true)] = ''; + do { + $data = @\fread($pipe, self::CHUNK_SIZE); + $read[$type] .= $data; + } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1]))); + if (!isset($read[$type][0])) { + unset($read[$type]); + } + if ($close && \feof($pipe)) { + \fclose($pipe); + unset($this->pipes[$type]); + } + } + $phabelReturn = $read; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function haveReadSupport() + { + $phabelReturn = $this->haveReadSupport; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function areOpen() + { + $phabelReturn = (bool) $this->pipes; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/process/Pipes/WindowsPipes.php b/vendor-bundle/symfony/process/Pipes/WindowsPipes.php new file mode 100644 index 000000000..b9d57fdc5 --- /dev/null +++ b/vendor-bundle/symfony/process/Pipes/WindowsPipes.php @@ -0,0 +1,227 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process\Pipes; + +use Phabel\Symfony\Component\Process\Exception\RuntimeException; +use Phabel\Symfony\Component\Process\Process; +/** + * WindowsPipes implementation uses temporary files as handles. + * + * @see https://bugs.php.net/51800 + * @see https://bugs.php.net/65650 + * + * @author Romain Neutron + * + * @internal + */ +class WindowsPipes extends AbstractPipes +{ + private $files = []; + private $fileHandles = []; + private $lockHandles = []; + private $readBytes = [Process::STDOUT => 0, Process::STDERR => 0]; + private $haveReadSupport; + public function __construct($input, $haveReadSupport) + { + if (!\is_bool($haveReadSupport)) { + if (!(\is_bool($haveReadSupport) || \is_numeric($haveReadSupport) || \is_string($haveReadSupport))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($haveReadSupport) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($haveReadSupport) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $haveReadSupport = (bool) $haveReadSupport; + } + } + $this->haveReadSupport = $haveReadSupport; + if ($this->haveReadSupport) { + // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big. + // Workaround for this problem is to use temporary files instead of pipes on Windows platform. + // + // @see https://bugs.php.net/51800 + $pipes = [Process::STDOUT => Process::OUT, Process::STDERR => Process::ERR]; + $tmpDir = \sys_get_temp_dir(); + $lastError = 'unknown reason'; + \set_error_handler(function ($type, $msg) use(&$lastError) { + $lastError = $msg; + }); + for ($i = 0;; ++$i) { + foreach ($pipes as $pipe => $name) { + $file = \sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); + if (!($h = \fopen($file . '.lock', 'w'))) { + if (\file_exists($file . '.lock')) { + continue 2; + } + \restore_error_handler(); + throw new RuntimeException('A temporary file could not be opened to write the process output: ' . $lastError); + } + if (!\flock($h, \LOCK_EX | \LOCK_NB)) { + continue 2; + } + if (isset($this->lockHandles[$pipe])) { + \flock($this->lockHandles[$pipe], \LOCK_UN); + \fclose($this->lockHandles[$pipe]); + } + $this->lockHandles[$pipe] = $h; + if (!($h = \fopen($file, 'w')) || !\fclose($h) || !($h = \fopen($file, 'r'))) { + \flock($this->lockHandles[$pipe], \LOCK_UN); + \fclose($this->lockHandles[$pipe]); + unset($this->lockHandles[$pipe]); + continue 2; + } + $this->fileHandles[$pipe] = $h; + $this->files[$pipe] = $file; + } + break; + } + \restore_error_handler(); + } + parent::__construct($input); + } + /** + * @return array + */ + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize ' . __CLASS__); + } + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__); + } + public function __destruct() + { + $this->close(); + } + /** + * {@inheritdoc} + */ + public function getDescriptors() + { + if (!$this->haveReadSupport) { + $nullstream = \fopen('NUL', 'c'); + $phabelReturn = [['pipe', 'r'], $nullstream, $nullstream]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = [['pipe', 'r'], ['file', 'NUL', 'w'], ['file', 'NUL', 'w']]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/51800) + // We're not using file handles as it can produce corrupted output https://bugs.php.net/65650 + // So we redirect output within the commandline and pass the nul device to the process + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function getFiles() + { + $phabelReturn = $this->files; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function readAndWrite($blocking, $close = \false) + { + if (!\is_bool($blocking)) { + if (!(\is_bool($blocking) || \is_numeric($blocking) || \is_string($blocking))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($blocking) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($blocking) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $blocking = (bool) $blocking; + } + } + if (!\is_bool($close)) { + if (!(\is_bool($close) || \is_numeric($close) || \is_string($close))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($close) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($close) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $close = (bool) $close; + } + } + $this->unblock(); + $w = $this->write(); + $read = $r = $e = []; + if ($blocking) { + if ($w) { + @\stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1000000.0); + } elseif ($this->fileHandles) { + \usleep(Process::TIMEOUT_PRECISION * 1000000.0); + } + } + foreach ($this->fileHandles as $type => $fileHandle) { + $data = \stream_get_contents($fileHandle, -1, $this->readBytes[$type]); + if (isset($data[0])) { + $this->readBytes[$type] += \strlen($data); + $read[$type] = $data; + } + if ($close) { + \ftruncate($fileHandle, 0); + \fclose($fileHandle); + \flock($this->lockHandles[$type], \LOCK_UN); + \fclose($this->lockHandles[$type]); + unset($this->fileHandles[$type], $this->lockHandles[$type]); + } + } + $phabelReturn = $read; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function haveReadSupport() + { + $phabelReturn = $this->haveReadSupport; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function areOpen() + { + $phabelReturn = $this->pipes && $this->fileHandles; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function close() + { + parent::close(); + foreach ($this->fileHandles as $type => $handle) { + \ftruncate($handle, 0); + \fclose($handle); + \flock($this->lockHandles[$type], \LOCK_UN); + \fclose($this->lockHandles[$type]); + } + $this->fileHandles = $this->lockHandles = []; + } +} diff --git a/vendor-bundle/symfony/process/Process.php b/vendor-bundle/symfony/process/Process.php new file mode 100644 index 000000000..aa3a725f7 --- /dev/null +++ b/vendor-bundle/symfony/process/Process.php @@ -0,0 +1,1847 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process; + +use Phabel\Symfony\Component\Process\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\Process\Exception\LogicException; +use Phabel\Symfony\Component\Process\Exception\ProcessFailedException; +use Phabel\Symfony\Component\Process\Exception\ProcessSignaledException; +use Phabel\Symfony\Component\Process\Exception\ProcessTimedOutException; +use Phabel\Symfony\Component\Process\Exception\RuntimeException; +use Phabel\Symfony\Component\Process\Pipes\PipesInterface; +use Phabel\Symfony\Component\Process\Pipes\UnixPipes; +use Phabel\Symfony\Component\Process\Pipes\WindowsPipes; +/** + * Process is a thin wrapper around proc_* functions to easily + * start independent PHP processes. + * + * @author Fabien Potencier + * @author Romain Neutron + */ +class Process implements \IteratorAggregate +{ + const ERR = 'err'; + const OUT = 'out'; + const STATUS_READY = 'ready'; + const STATUS_STARTED = 'started'; + const STATUS_TERMINATED = 'terminated'; + const STDIN = 0; + const STDOUT = 1; + const STDERR = 2; + // Timeout Precision in seconds. + const TIMEOUT_PRECISION = 0.2; + const ITER_NON_BLOCKING = 1; + // By default, iterating over outputs is a blocking call, use this flag to make it non-blocking + const ITER_KEEP_OUTPUT = 2; + // By default, outputs are cleared while iterating, use this flag to keep them in memory + const ITER_SKIP_OUT = 4; + // Use this flag to skip STDOUT while iterating + const ITER_SKIP_ERR = 8; + // Use this flag to skip STDERR while iterating + private $callback; + private $hasCallback = \false; + private $commandline; + private $cwd; + private $env; + private $input; + private $starttime; + private $lastOutputTime; + private $timeout; + private $idleTimeout; + private $exitcode; + private $fallbackStatus = []; + private $processInformation; + private $outputDisabled = \false; + private $stdout; + private $stderr; + private $process; + private $status = self::STATUS_READY; + private $incrementalOutputOffset = 0; + private $incrementalErrorOutputOffset = 0; + private $tty = \false; + private $pty; + private $options = ['suppress_errors' => \true, 'bypass_shell' => \true]; + private $useFileHandles = \false; + /** @var PipesInterface */ + private $processPipes; + private $latestSignal; + private static $sigchild; + /** + * Exit codes translation table. + * + * User-defined errors must use exit codes in the 64-113 range. + */ + public static $exitCodes = [ + 0 => 'OK', + 1 => 'General error', + 2 => 'Misuse of shell builtins', + 126 => 'Invoked command cannot execute', + 127 => 'Command not found', + 128 => 'Invalid exit argument', + // signals + 129 => 'Hangup', + 130 => 'Interrupt', + 131 => 'Quit and dump core', + 132 => 'Illegal instruction', + 133 => 'Trace/breakpoint trap', + 134 => 'Process aborted', + 135 => 'Bus error: "access to undefined portion of memory object"', + 136 => 'Floating point exception: "erroneous arithmetic operation"', + 137 => 'Kill (terminate immediately)', + 138 => 'User-defined 1', + 139 => 'Segmentation violation', + 140 => 'User-defined 2', + 141 => 'Write to pipe with no one reading', + 142 => 'Signal raised by alarm', + 143 => 'Termination (request to terminate)', + // 144 - not defined + 145 => 'Child process terminated, stopped (or continued*)', + 146 => 'Continue if stopped', + 147 => 'Stop executing temporarily', + 148 => 'Terminal stop signal', + 149 => 'Background process attempting to read from tty ("in")', + 150 => 'Background process attempting to write to tty ("out")', + 151 => 'Urgent data available on socket', + 152 => 'CPU time limit exceeded', + 153 => 'File size limit exceeded', + 154 => 'Signal raised by timer counting virtual time: "virtual timer expired"', + 155 => 'Profiling timer expired', + // 156 - not defined + 157 => 'Pollable event', + // 158 - not defined + 159 => 'Bad syscall', + ]; + /** + * @param array $command The command to run and its arguments listed as separate entries + * @param string|null $cwd The working directory or null to use the working dir of the current PHP process + * @param array|null $env The environment variables or null to use the same environment as the current PHP process + * @param mixed $input The input as stream resource, scalar or \Traversable, or null for no input + * @param int|float|null $timeout The timeout in seconds or null to disable + * + * @throws LogicException When proc_open is not installed + */ + public function __construct(array $command, $cwd = null, array $env = null, $input = null, $timeout = 60) + { + if (!\is_null($cwd)) { + if (!\is_string($cwd)) { + if (!(\is_string($cwd) || \is_object($cwd) && \method_exists($cwd, '__toString') || (\is_bool($cwd) || \is_numeric($cwd)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($cwd) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cwd) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cwd = (string) $cwd; + } + } + } + if (!\is_null($timeout)) { + if (!\is_float($timeout)) { + if (!(\is_bool($timeout) || \is_numeric($timeout))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($timeout) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeout) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $timeout = (double) $timeout; + } + } + } + if (!\function_exists('proc_open')) { + throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.'); + } + $this->commandline = $command; + $this->cwd = $cwd; + // on Windows, if the cwd changed via chdir(), proc_open defaults to the dir where PHP was started + // on Gnu/Linux, PHP builds with --enable-maintainer-zts are also affected + // @see : https://bugs.php.net/51800 + // @see : https://bugs.php.net/50524 + if (null === $this->cwd && (\defined('ZEND_THREAD_SAFE') || '\\' === \DIRECTORY_SEPARATOR)) { + $this->cwd = \getcwd(); + } + if (null !== $env) { + $this->setEnv($env); + } + $this->setInput($input); + $this->setTimeout($timeout); + $this->useFileHandles = '\\' === \DIRECTORY_SEPARATOR; + $this->pty = \false; + } + /** + * Creates a Process instance as a command-line to be run in a shell wrapper. + * + * Command-lines are parsed by the shell of your OS (/bin/sh on Unix-like, cmd.exe on Windows.) + * This allows using e.g. pipes or conditional execution. In this mode, signals are sent to the + * shell wrapper and not to your commands. + * + * In order to inject dynamic values into command-lines, we strongly recommend using placeholders. + * This will save escaping values, which is not portable nor secure anyway: + * + * $process = Process::fromShellCommandline('my_command "$MY_VAR"'); + * $process->run(null, ['MY_VAR' => $theValue]); + * + * @param string $command The command line to pass to the shell of the OS + * @param string|null $cwd The working directory or null to use the working dir of the current PHP process + * @param array|null $env The environment variables or null to use the same environment as the current PHP process + * @param mixed $input The input as stream resource, scalar or \Traversable, or null for no input + * @param int|float|null $timeout The timeout in seconds or null to disable + * + * @return static + * + * @throws LogicException When proc_open is not installed + */ + public static function fromShellCommandline($command, $cwd = null, array $env = null, $input = null, $timeout = 60) + { + if (!\is_string($command)) { + if (!(\is_string($command) || \is_object($command) && \method_exists($command, '__toString') || (\is_bool($command) || \is_numeric($command)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($command) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($command) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $command = (string) $command; + } + } + if (!\is_null($cwd)) { + if (!\is_string($cwd)) { + if (!(\is_string($cwd) || \is_object($cwd) && \method_exists($cwd, '__toString') || (\is_bool($cwd) || \is_numeric($cwd)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($cwd) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cwd) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cwd = (string) $cwd; + } + } + } + if (!\is_null($timeout)) { + if (!\is_float($timeout)) { + if (!(\is_bool($timeout) || \is_numeric($timeout))) { + throw new \TypeError(__METHOD__ . '(): Argument #5 ($timeout) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeout) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $timeout = (double) $timeout; + } + } + } + $process = new static([], $cwd, $env, $input, $timeout); + $process->commandline = $command; + return $process; + } + /** + * @return array + */ + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize ' . __CLASS__); + } + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__); + } + public function __destruct() + { + if (isset($this->options['create_new_console']) ? $this->options['create_new_console'] : \false) { + $this->processPipes->close(); + } else { + $this->stop(0); + } + } + public function __clone() + { + $this->resetProcessData(); + } + /** + * Runs the process. + * + * The callback receives the type of output (out or err) and + * some bytes from the output in real-time. It allows to have feedback + * from the independent process during execution. + * + * The STDOUT and STDERR are also available after the process is finished + * via the getOutput() and getErrorOutput() methods. + * + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @return int The exit status code + * + * @throws RuntimeException When process can't be launched + * @throws RuntimeException When process is already running + * @throws ProcessTimedOutException When process timed out + * @throws ProcessSignaledException When process stopped after receiving signal + * @throws LogicException In case a callback is provided and output has been disabled + * + * @final + */ + public function run(callable $callback = null, array $env = []) + { + $this->start($callback, $env); + $phabelReturn = $this->wait(); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Runs the process. + * + * This is identical to run() except that an exception is thrown if the process + * exits with a non-zero exit code. + * + * @return $this + * + * @throws ProcessFailedException if the process didn't terminate successfully + * + * @final + */ + public function mustRun(callable $callback = null, array $env = []) + { + if (0 !== $this->run($callback, $env)) { + throw new ProcessFailedException($this); + } + $phabelReturn = $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Starts the process and returns after writing the input to STDIN. + * + * This method blocks until all STDIN data is sent to the process then it + * returns while the process runs in the background. + * + * The termination of the process can be awaited with wait(). + * + * The callback receives the type of output (out or err) and some bytes from + * the output in real-time while writing the standard input to the process. + * It allows to have feedback from the independent process during execution. + * + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @throws RuntimeException When process can't be launched + * @throws RuntimeException When process is already running + * @throws LogicException In case a callback is provided and output has been disabled + */ + public function start(callable $callback = null, array $env = []) + { + if ($this->isRunning()) { + throw new RuntimeException('Process is already running.'); + } + $this->resetProcessData(); + $this->starttime = $this->lastOutputTime = \microtime(\true); + $this->callback = $this->buildCallback($callback); + $this->hasCallback = null !== $callback; + $descriptors = $this->getDescriptors(); + if ($this->env) { + $env += $this->env; + } + $env += $this->getDefaultEnv(); + if (\is_array($commandline = $this->commandline)) { + $commandline = \implode(' ', \array_map([$this, 'escapeArgument'], $commandline)); + if ('\\' !== \DIRECTORY_SEPARATOR) { + // exec is mandatory to deal with sending a signal to the process + $commandline = 'exec ' . $commandline; + } + } else { + $commandline = $this->replacePlaceholders($commandline, $env); + } + if ('\\' === \DIRECTORY_SEPARATOR) { + $commandline = $this->prepareWindowsCommandLine($commandline, $env); + } elseif (!$this->useFileHandles && $this->isSigchildEnabled()) { + // last exit code is output on the fourth pipe and caught to work around --enable-sigchild + $descriptors[3] = ['pipe', 'w']; + // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input + $commandline = '{ (' . $commandline . ') <&3 3<&- 3>/dev/null & } 3<&0;'; + $commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code'; + // Workaround for the bug, when PTS functionality is enabled. + // @see : https://bugs.php.net/69442 + $ptsWorkaround = \fopen(__FILE__, 'r'); + } + $envPairs = []; + foreach ($env as $k => $v) { + if (\false !== $v) { + $envPairs[] = $k . '=' . $v; + } + } + if (!\is_dir($this->cwd)) { + throw new RuntimeException(\sprintf('The provided cwd "%s" does not exist.', $this->cwd)); + } + $this->process = @\proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options); + if (!\is_resource($this->process)) { + throw new RuntimeException('Unable to launch a new process.'); + } + $this->status = self::STATUS_STARTED; + if (isset($descriptors[3])) { + $this->fallbackStatus['pid'] = (int) \fgets($this->processPipes->pipes[3]); + } + if ($this->tty) { + return; + } + $this->updateStatus(\false); + $this->checkTimeout(); + } + /** + * Restarts the process. + * + * Be warned that the process is cloned before being started. + * + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @return static + * + * @throws RuntimeException When process can't be launched + * @throws RuntimeException When process is already running + * + * @see start() + * + * @final + */ + public function restart(callable $callback = null, array $env = []) + { + if ($this->isRunning()) { + throw new RuntimeException('Process is already running.'); + } + $process = clone $this; + $process->start($callback, $env); + $phabelReturn = $process; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Waits for the process to terminate. + * + * The callback receives the type of output (out or err) and some bytes + * from the output in real-time while writing the standard input to the process. + * It allows to have feedback from the independent process during execution. + * + * @param callable|null $callback A valid PHP callback + * + * @return int The exitcode of the process + * + * @throws ProcessTimedOutException When process timed out + * @throws ProcessSignaledException When process stopped after receiving signal + * @throws LogicException When process is not yet started + */ + public function wait(callable $callback = null) + { + $this->requireProcessIsStarted(__FUNCTION__); + $this->updateStatus(\false); + if (null !== $callback) { + if (!$this->processPipes->haveReadSupport()) { + $this->stop(0); + throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".'); + } + $this->callback = $this->buildCallback($callback); + } + do { + $this->checkTimeout(); + $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen(); + $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running); + } while ($running); + while ($this->isRunning()) { + $this->checkTimeout(); + \usleep(1000); + } + if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) { + throw new ProcessSignaledException($this); + } + return $this->exitcode; + } + /** + * Waits until the callback returns true. + * + * The callback receives the type of output (out or err) and some bytes + * from the output in real-time while writing the standard input to the process. + * It allows to have feedback from the independent process during execution. + * + * @throws RuntimeException When process timed out + * @throws LogicException When process is not yet started + * @throws ProcessTimedOutException In case the timeout was reached + */ + public function waitUntil(callable $callback) + { + $this->requireProcessIsStarted(__FUNCTION__); + $this->updateStatus(\false); + if (!$this->processPipes->haveReadSupport()) { + $this->stop(0); + throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".'); + } + $callback = $this->buildCallback($callback); + $ready = \false; + while (\true) { + $this->checkTimeout(); + $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen(); + $output = $this->processPipes->readAndWrite($running, '\\' !== \DIRECTORY_SEPARATOR || !$running); + foreach ($output as $type => $data) { + if (3 !== $type) { + $ready = $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data) || $ready; + } elseif (!isset($this->fallbackStatus['signaled'])) { + $this->fallbackStatus['exitcode'] = (int) $data; + } + } + if ($ready) { + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if (!$running) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + \usleep(1000); + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** + * Returns the Pid (process identifier), if applicable. + * + * @return int|null The process id if running, null otherwise + */ + public function getPid() + { + return $this->isRunning() ? $this->processInformation['pid'] : null; + } + /** + * Sends a POSIX signal to the process. + * + * @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants) + * + * @return $this + * + * @throws LogicException In case the process is not running + * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed + * @throws RuntimeException In case of failure + */ + public function signal($signal) + { + if (!\is_int($signal)) { + if (!(\is_bool($signal) || \is_numeric($signal))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($signal) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signal) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signal = (int) $signal; + } + } + $this->doSignal($signal, \true); + return $this; + } + /** + * Disables fetching output and error output from the underlying process. + * + * @return $this + * + * @throws RuntimeException In case the process is already running + * @throws LogicException if an idle timeout is set + */ + public function disableOutput() + { + if ($this->isRunning()) { + throw new RuntimeException('Disabling output while the process is running is not possible.'); + } + if (null !== $this->idleTimeout) { + throw new LogicException('Output can not be disabled while an idle timeout is set.'); + } + $this->outputDisabled = \true; + return $this; + } + /** + * Enables fetching output and error output from the underlying process. + * + * @return $this + * + * @throws RuntimeException In case the process is already running + */ + public function enableOutput() + { + if ($this->isRunning()) { + throw new RuntimeException('Enabling output while the process is running is not possible.'); + } + $this->outputDisabled = \false; + return $this; + } + /** + * Returns true in case the output is disabled, false otherwise. + * + * @return bool + */ + public function isOutputDisabled() + { + return $this->outputDisabled; + } + /** + * Returns the current output of the process (STDOUT). + * + * @return string The process output + * + * @throws LogicException in case the output has been disabled + * @throws LogicException In case the process is not started + */ + public function getOutput() + { + $this->readPipesForOutput(__FUNCTION__); + if (\false === ($ret = \stream_get_contents($this->stdout, -1, 0))) { + return ''; + } + return $ret; + } + /** + * Returns the output incrementally. + * + * In comparison with the getOutput method which always return the whole + * output, this one returns the new output since the last call. + * + * @return string The process output since the last call + * + * @throws LogicException in case the output has been disabled + * @throws LogicException In case the process is not started + */ + public function getIncrementalOutput() + { + $this->readPipesForOutput(__FUNCTION__); + $latest = \stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset); + $this->incrementalOutputOffset = \ftell($this->stdout); + if (\false === $latest) { + return ''; + } + return $latest; + } + /** + * Returns an iterator to the output of the process, with the output type as keys (Process::OUT/ERR). + * + * @param int $flags A bit field of Process::ITER_* flags + * + * @throws LogicException in case the output has been disabled + * @throws LogicException In case the process is not started + * + * @return \Generator + */ + public function getIterator($flags = 0) + { + if (!\is_int($flags)) { + if (!(\is_bool($flags) || \is_numeric($flags))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($flags) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($flags) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $flags = (int) $flags; + } + } + $this->readPipesForOutput(__FUNCTION__, \false); + $clearOutput = !(self::ITER_KEEP_OUTPUT & $flags); + $blocking = !(self::ITER_NON_BLOCKING & $flags); + $yieldOut = !(self::ITER_SKIP_OUT & $flags); + $yieldErr = !(self::ITER_SKIP_ERR & $flags); + while (null !== $this->callback || $yieldOut && !\feof($this->stdout) || $yieldErr && !\feof($this->stderr)) { + if ($yieldOut) { + $out = \stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset); + if (isset($out[0])) { + if ($clearOutput) { + $this->clearOutput(); + } else { + $this->incrementalOutputOffset = \ftell($this->stdout); + } + (yield self::OUT => $out); + } + } + if ($yieldErr) { + $err = \stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset); + if (isset($err[0])) { + if ($clearOutput) { + $this->clearErrorOutput(); + } else { + $this->incrementalErrorOutputOffset = \ftell($this->stderr); + } + (yield self::ERR => $err); + } + } + if (!$blocking && !isset($out[0]) && !isset($err[0])) { + (yield self::OUT => ''); + } + $this->checkTimeout(); + $this->readPipesForOutput(__FUNCTION__, $blocking); + } + } + /** + * Clears the process output. + * + * @return $this + */ + public function clearOutput() + { + \ftruncate($this->stdout, 0); + \fseek($this->stdout, 0); + $this->incrementalOutputOffset = 0; + return $this; + } + /** + * Returns the current error output of the process (STDERR). + * + * @return string The process error output + * + * @throws LogicException in case the output has been disabled + * @throws LogicException In case the process is not started + */ + public function getErrorOutput() + { + $this->readPipesForOutput(__FUNCTION__); + if (\false === ($ret = \stream_get_contents($this->stderr, -1, 0))) { + return ''; + } + return $ret; + } + /** + * Returns the errorOutput incrementally. + * + * In comparison with the getErrorOutput method which always return the + * whole error output, this one returns the new error output since the last + * call. + * + * @return string The process error output since the last call + * + * @throws LogicException in case the output has been disabled + * @throws LogicException In case the process is not started + */ + public function getIncrementalErrorOutput() + { + $this->readPipesForOutput(__FUNCTION__); + $latest = \stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset); + $this->incrementalErrorOutputOffset = \ftell($this->stderr); + if (\false === $latest) { + return ''; + } + return $latest; + } + /** + * Clears the process output. + * + * @return $this + */ + public function clearErrorOutput() + { + \ftruncate($this->stderr, 0); + \fseek($this->stderr, 0); + $this->incrementalErrorOutputOffset = 0; + return $this; + } + /** + * Returns the exit code returned by the process. + * + * @return int|null The exit status code, null if the Process is not terminated + */ + public function getExitCode() + { + $this->updateStatus(\false); + return $this->exitcode; + } + /** + * Returns a string representation for the exit code returned by the process. + * + * This method relies on the Unix exit code status standardization + * and might not be relevant for other operating systems. + * + * @return string|null A string representation for the exit status code, null if the Process is not terminated + * + * @see http://tldp.org/LDP/abs/html/exitcodes.html + * @see http://en.wikipedia.org/wiki/Unix_signal + */ + public function getExitCodeText() + { + if (null === ($exitcode = $this->getExitCode())) { + return null; + } + return isset(self::$exitCodes[$exitcode]) ? self::$exitCodes[$exitcode] : 'Unknown error'; + } + /** + * Checks if the process ended successfully. + * + * @return bool true if the process ended successfully, false otherwise + */ + public function isSuccessful() + { + return 0 === $this->getExitCode(); + } + /** + * Returns true if the child process has been terminated by an uncaught signal. + * + * It always returns false on Windows. + * + * @return bool + * + * @throws LogicException In case the process is not terminated + */ + public function hasBeenSignaled() + { + $this->requireProcessIsTerminated(__FUNCTION__); + return $this->processInformation['signaled']; + } + /** + * Returns the number of the signal that caused the child process to terminate its execution. + * + * It is only meaningful if hasBeenSignaled() returns true. + * + * @return int + * + * @throws RuntimeException In case --enable-sigchild is activated + * @throws LogicException In case the process is not terminated + */ + public function getTermSignal() + { + $this->requireProcessIsTerminated(__FUNCTION__); + if ($this->isSigchildEnabled() && -1 === $this->processInformation['termsig']) { + throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal can not be retrieved.'); + } + return $this->processInformation['termsig']; + } + /** + * Returns true if the child process has been stopped by a signal. + * + * It always returns false on Windows. + * + * @return bool + * + * @throws LogicException In case the process is not terminated + */ + public function hasBeenStopped() + { + $this->requireProcessIsTerminated(__FUNCTION__); + return $this->processInformation['stopped']; + } + /** + * Returns the number of the signal that caused the child process to stop its execution. + * + * It is only meaningful if hasBeenStopped() returns true. + * + * @return int + * + * @throws LogicException In case the process is not terminated + */ + public function getStopSignal() + { + $this->requireProcessIsTerminated(__FUNCTION__); + return $this->processInformation['stopsig']; + } + /** + * Checks if the process is currently running. + * + * @return bool true if the process is currently running, false otherwise + */ + public function isRunning() + { + if (self::STATUS_STARTED !== $this->status) { + return \false; + } + $this->updateStatus(\false); + return $this->processInformation['running']; + } + /** + * Checks if the process has been started with no regard to the current state. + * + * @return bool true if status is ready, false otherwise + */ + public function isStarted() + { + return self::STATUS_READY != $this->status; + } + /** + * Checks if the process is terminated. + * + * @return bool true if process is terminated, false otherwise + */ + public function isTerminated() + { + $this->updateStatus(\false); + return self::STATUS_TERMINATED == $this->status; + } + /** + * Gets the process status. + * + * The status is one of: ready, started, terminated. + * + * @return string The current process status + */ + public function getStatus() + { + $this->updateStatus(\false); + return $this->status; + } + /** + * Stops the process. + * + * @param int|float $timeout The timeout in seconds + * @param int $signal A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9) + * + * @return int|null The exit-code of the process or null if it's not running + */ + public function stop($timeout = 10, $signal = null) + { + if (!\is_float($timeout)) { + if (!(\is_bool($timeout) || \is_numeric($timeout))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($timeout) must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeout) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $timeout = (double) $timeout; + } + } + if (!\is_null($signal)) { + if (!\is_int($signal)) { + if (!(\is_bool($signal) || \is_numeric($signal))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($signal) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signal) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signal = (int) $signal; + } + } + } + $timeoutMicro = \microtime(\true) + $timeout; + if ($this->isRunning()) { + // given SIGTERM may not be defined and that "proc_terminate" uses the constant value and not the constant itself, we use the same here + $this->doSignal(15, \false); + do { + \usleep(1000); + } while ($this->isRunning() && \microtime(\true) < $timeoutMicro); + if ($this->isRunning()) { + // Avoid exception here: process is supposed to be running, but it might have stopped just + // after this line. In any case, let's silently discard the error, we cannot do anything. + $this->doSignal($signal ?: 9, \false); + } + } + if ($this->isRunning()) { + if (isset($this->fallbackStatus['pid'])) { + unset($this->fallbackStatus['pid']); + return $this->stop(0, $signal); + } + $this->close(); + } + return $this->exitcode; + } + /** + * Adds a line to the STDOUT stream. + * + * @internal + */ + public function addOutput($line) + { + if (!\is_string($line)) { + if (!(\is_string($line) || \is_object($line) && \method_exists($line, '__toString') || (\is_bool($line) || \is_numeric($line)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($line) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($line) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $line = (string) $line; + } + } + $this->lastOutputTime = \microtime(\true); + \fseek($this->stdout, 0, \SEEK_END); + \fwrite($this->stdout, $line); + \fseek($this->stdout, $this->incrementalOutputOffset); + } + /** + * Adds a line to the STDERR stream. + * + * @internal + */ + public function addErrorOutput($line) + { + if (!\is_string($line)) { + if (!(\is_string($line) || \is_object($line) && \method_exists($line, '__toString') || (\is_bool($line) || \is_numeric($line)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($line) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($line) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $line = (string) $line; + } + } + $this->lastOutputTime = \microtime(\true); + \fseek($this->stderr, 0, \SEEK_END); + \fwrite($this->stderr, $line); + \fseek($this->stderr, $this->incrementalErrorOutputOffset); + } + /** + * Gets the last output time in seconds. + * + * @return float|null The last output time in seconds or null if it isn't started + */ + public function getLastOutputTime() + { + $phabelReturn = $this->lastOutputTime; + if (!\is_null($phabelReturn)) { + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + } + return $phabelReturn; + } + /** + * Gets the command line to be executed. + * + * @return string The command to execute + */ + public function getCommandLine() + { + return \is_array($this->commandline) ? \implode(' ', \array_map([$this, 'escapeArgument'], $this->commandline)) : $this->commandline; + } + /** + * Gets the process timeout (max. runtime). + * + * @return float|null The timeout in seconds or null if it's disabled + */ + public function getTimeout() + { + return $this->timeout; + } + /** + * Gets the process idle timeout (max. time since last output). + * + * @return float|null The timeout in seconds or null if it's disabled + */ + public function getIdleTimeout() + { + return $this->idleTimeout; + } + /** + * Sets the process timeout (max. runtime) in seconds. + * + * To disable the timeout, set this value to null. + * + * @return $this + * + * @throws InvalidArgumentException if the timeout is negative + */ + public function setTimeout($timeout) + { + if (!\is_null($timeout)) { + if (!\is_float($timeout)) { + if (!(\is_bool($timeout) || \is_numeric($timeout))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($timeout) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeout) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $timeout = (double) $timeout; + } + } + } + $this->timeout = $this->validateTimeout($timeout); + return $this; + } + /** + * Sets the process idle timeout (max. time since last output) in seconds. + * + * To disable the timeout, set this value to null. + * + * @return $this + * + * @throws LogicException if the output is disabled + * @throws InvalidArgumentException if the timeout is negative + */ + public function setIdleTimeout($timeout) + { + if (!\is_null($timeout)) { + if (!\is_float($timeout)) { + if (!(\is_bool($timeout) || \is_numeric($timeout))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($timeout) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeout) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $timeout = (double) $timeout; + } + } + } + if (null !== $timeout && $this->outputDisabled) { + throw new LogicException('Idle timeout can not be set while the output is disabled.'); + } + $this->idleTimeout = $this->validateTimeout($timeout); + return $this; + } + /** + * Enables or disables the TTY mode. + * + * @return $this + * + * @throws RuntimeException In case the TTY mode is not supported + */ + public function setTty($tty) + { + if (!\is_bool($tty)) { + if (!(\is_bool($tty) || \is_numeric($tty) || \is_string($tty))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($tty) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($tty) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $tty = (bool) $tty; + } + } + if ('\\' === \DIRECTORY_SEPARATOR && $tty) { + throw new RuntimeException('TTY mode is not supported on Windows platform.'); + } + if ($tty && !self::isTtySupported()) { + throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.'); + } + $this->tty = $tty; + return $this; + } + /** + * Checks if the TTY mode is enabled. + * + * @return bool true if the TTY mode is enabled, false otherwise + */ + public function isTty() + { + return $this->tty; + } + /** + * Sets PTY mode. + * + * @return $this + */ + public function setPty($bool) + { + if (!\is_bool($bool)) { + if (!(\is_bool($bool) || \is_numeric($bool) || \is_string($bool))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($bool) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($bool) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $bool = (bool) $bool; + } + } + $this->pty = $bool; + return $this; + } + /** + * Returns PTY state. + * + * @return bool + */ + public function isPty() + { + return $this->pty; + } + /** + * Gets the working directory. + * + * @return string|null The current working directory or null on failure + */ + public function getWorkingDirectory() + { + if (null === $this->cwd) { + // getcwd() will return false if any one of the parent directories does not have + // the readable or search mode set, even if the current directory does + return \getcwd() ?: null; + } + return $this->cwd; + } + /** + * Sets the current working directory. + * + * @return $this + */ + public function setWorkingDirectory($cwd) + { + if (!\is_string($cwd)) { + if (!(\is_string($cwd) || \is_object($cwd) && \method_exists($cwd, '__toString') || (\is_bool($cwd) || \is_numeric($cwd)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($cwd) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cwd) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cwd = (string) $cwd; + } + } + $this->cwd = $cwd; + return $this; + } + /** + * Gets the environment variables. + * + * @return array The current environment variables + */ + public function getEnv() + { + return $this->env; + } + /** + * Sets the environment variables. + * + * Each environment variable value should be a string. + * If it is an array, the variable is ignored. + * If it is false or null, it will be removed when + * env vars are otherwise inherited. + * + * That happens in PHP when 'argv' is registered into + * the $_ENV array for instance. + * + * @param array $env The new environment variables + * + * @return $this + */ + public function setEnv(array $env) + { + // Process can not handle env values that are arrays + $env = \array_filter($env, function ($value) { + return !\is_array($value); + }); + $this->env = $env; + return $this; + } + /** + * Gets the Process input. + * + * @return resource|string|\Iterator|null The Process input + */ + public function getInput() + { + return $this->input; + } + /** + * Sets the input. + * + * This content will be passed to the underlying process standard input. + * + * @param string|int|float|bool|resource|\Traversable|null $input The content + * + * @return $this + * + * @throws LogicException In case the process is running + */ + public function setInput($input) + { + if ($this->isRunning()) { + throw new LogicException('Input can not be set while the process is running.'); + } + $this->input = ProcessUtils::validateInput(__METHOD__, $input); + return $this; + } + /** + * Performs a check between the timeout definition and the time the process started. + * + * In case you run a background process (with the start method), you should + * trigger this method regularly to ensure the process timeout + * + * @throws ProcessTimedOutException In case the timeout was reached + */ + public function checkTimeout() + { + if (self::STATUS_STARTED !== $this->status) { + return; + } + if (null !== $this->timeout && $this->timeout < \microtime(\true) - $this->starttime) { + $this->stop(0); + throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL); + } + if (null !== $this->idleTimeout && $this->idleTimeout < \microtime(\true) - $this->lastOutputTime) { + $this->stop(0); + throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE); + } + } + /** + * @throws LogicException in case process is not started + */ + public function getStartTime() + { + if (!$this->isStarted()) { + throw new LogicException('Start time is only available after process start.'); + } + $phabelReturn = $this->starttime; + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Defines options to pass to the underlying proc_open(). + * + * @see https://php.net/proc_open for the options supported by PHP. + * + * Enabling the "create_new_console" option allows a subprocess to continue + * to run after the main process exited, on both Windows and *nix + */ + public function setOptions(array $options) + { + if ($this->isRunning()) { + throw new RuntimeException('Setting options while the process is running is not possible.'); + } + $defaultOptions = $this->options; + $existingOptions = ['blocking_pipes', 'create_process_group', 'create_new_console']; + foreach ($options as $key => $value) { + if (!\in_array($key, $existingOptions)) { + $this->options = $defaultOptions; + throw new LogicException(\sprintf('Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, \implode('", "', $existingOptions))); + } + $this->options[$key] = $value; + } + } + /** + * Returns whether TTY is supported on the current operating system. + */ + public static function isTtySupported() + { + static $isTtySupported; + if (null === $isTtySupported) { + $isTtySupported = (bool) @\proc_open('echo 1 >/dev/null', [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']], $pipes); + } + $phabelReturn = $isTtySupported; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Returns whether PTY is supported on the current operating system. + * + * @return bool + */ + public static function isPtySupported() + { + static $result; + if (null !== $result) { + return $result; + } + if ('\\' === \DIRECTORY_SEPARATOR) { + return $result = \false; + } + return $result = (bool) @\proc_open('echo 1 >/dev/null', [['pty'], ['pty'], ['pty']], $pipes); + } + /** + * Creates the descriptors needed by the proc_open. + */ + private function getDescriptors() + { + if ($this->input instanceof \Iterator) { + $this->input->rewind(); + } + if ('\\' === \DIRECTORY_SEPARATOR) { + $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $this->hasCallback); + } else { + $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $this->hasCallback); + } + $phabelReturn = $this->processPipes->getDescriptors(); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Builds up the callback used by wait(). + * + * The callbacks adds all occurred output to the specific buffer and calls + * the user callback (if present) with the received output. + * + * @param callable|null $callback The user defined PHP callback + * + * @return \Closure A PHP closure + */ + protected function buildCallback(callable $callback = null) + { + if ($this->outputDisabled) { + return function ($type, $data) use($callback) { + $phabelReturn = null !== $callback && $callback($type, $data); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + }; + } + $out = self::OUT; + return function ($type, $data) use($callback, $out) { + if ($out == $type) { + $this->addOutput($data); + } else { + $this->addErrorOutput($data); + } + $phabelReturn = null !== $callback && $callback($type, $data); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + }; + } + /** + * Updates the status of the process, reads pipes. + * + * @param bool $blocking Whether to use a blocking read call + */ + protected function updateStatus($blocking) + { + if (!\is_bool($blocking)) { + if (!(\is_bool($blocking) || \is_numeric($blocking) || \is_string($blocking))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($blocking) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($blocking) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $blocking = (bool) $blocking; + } + } + if (self::STATUS_STARTED !== $this->status) { + return; + } + $this->processInformation = \proc_get_status($this->process); + $running = $this->processInformation['running']; + $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running); + if ($this->fallbackStatus && $this->isSigchildEnabled()) { + $this->processInformation = $this->fallbackStatus + $this->processInformation; + } + if (!$running) { + $this->close(); + } + } + /** + * Returns whether PHP has been compiled with the '--enable-sigchild' option or not. + * + * @return bool + */ + protected function isSigchildEnabled() + { + if (null !== self::$sigchild) { + return self::$sigchild; + } + if (!\function_exists('phpinfo')) { + return self::$sigchild = \false; + } + \ob_start(); + \phpinfo(\INFO_GENERAL); + return self::$sigchild = \str_contains(\ob_get_clean(), '--enable-sigchild'); + } + /** + * Reads pipes for the freshest output. + * + * @param string $caller The name of the method that needs fresh outputs + * @param bool $blocking Whether to use blocking calls or not + * + * @throws LogicException in case output has been disabled or process is not started + */ + private function readPipesForOutput($caller, $blocking = \false) + { + if (!\is_string($caller)) { + if (!(\is_string($caller) || \is_object($caller) && \method_exists($caller, '__toString') || (\is_bool($caller) || \is_numeric($caller)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($caller) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($caller) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $caller = (string) $caller; + } + } + if (!\is_bool($blocking)) { + if (!(\is_bool($blocking) || \is_numeric($blocking) || \is_string($blocking))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($blocking) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($blocking) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $blocking = (bool) $blocking; + } + } + if ($this->outputDisabled) { + throw new LogicException('Output has been disabled.'); + } + $this->requireProcessIsStarted($caller); + $this->updateStatus($blocking); + } + /** + * Validates and returns the filtered timeout. + * + * @throws InvalidArgumentException if the given timeout is a negative number + */ + private function validateTimeout($timeout) + { + if (!\is_null($timeout)) { + if (!\is_float($timeout)) { + if (!(\is_bool($timeout) || \is_numeric($timeout))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($timeout) must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($timeout) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $timeout = (double) $timeout; + } + } + } + $timeout = (float) $timeout; + if (0.0 === $timeout) { + $timeout = null; + } elseif ($timeout < 0) { + throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.'); + } + $phabelReturn = $timeout; + if (!\is_null($phabelReturn)) { + if (!\is_float($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?float, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (double) $phabelReturn; + } + } + } + return $phabelReturn; + } + /** + * Reads pipes, executes callback. + * + * @param bool $blocking Whether to use blocking calls or not + * @param bool $close Whether to close file handles or not + */ + private function readPipes($blocking, $close) + { + if (!\is_bool($blocking)) { + if (!(\is_bool($blocking) || \is_numeric($blocking) || \is_string($blocking))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($blocking) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($blocking) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $blocking = (bool) $blocking; + } + } + if (!\is_bool($close)) { + if (!(\is_bool($close) || \is_numeric($close) || \is_string($close))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($close) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($close) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $close = (bool) $close; + } + } + $result = $this->processPipes->readAndWrite($blocking, $close); + $callback = $this->callback; + foreach ($result as $type => $data) { + if (3 !== $type) { + $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data); + } elseif (!isset($this->fallbackStatus['signaled'])) { + $this->fallbackStatus['exitcode'] = (int) $data; + } + } + } + /** + * Closes process resource, closes file handles, sets the exitcode. + * + * @return int The exitcode + */ + private function close() + { + $this->processPipes->close(); + if (\is_resource($this->process)) { + \proc_close($this->process); + } + $this->exitcode = $this->processInformation['exitcode']; + $this->status = self::STATUS_TERMINATED; + if (-1 === $this->exitcode) { + if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) { + // if process has been signaled, no exitcode but a valid termsig, apply Unix convention + $this->exitcode = 128 + $this->processInformation['termsig']; + } elseif ($this->isSigchildEnabled()) { + $this->processInformation['signaled'] = \true; + $this->processInformation['termsig'] = -1; + } + } + // Free memory from self-reference callback created by buildCallback + // Doing so in other contexts like __destruct or by garbage collector is ineffective + // Now pipes are closed, so the callback is no longer necessary + $this->callback = null; + $phabelReturn = $this->exitcode; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Resets data related to the latest run of the process. + */ + private function resetProcessData() + { + $this->starttime = null; + $this->callback = null; + $this->exitcode = null; + $this->fallbackStatus = []; + $this->processInformation = null; + $this->stdout = \fopen('php://temp/maxmemory:' . 1024 * 1024, 'w+'); + $this->stderr = \fopen('php://temp/maxmemory:' . 1024 * 1024, 'w+'); + $this->process = null; + $this->latestSignal = null; + $this->status = self::STATUS_READY; + $this->incrementalOutputOffset = 0; + $this->incrementalErrorOutputOffset = 0; + } + /** + * Sends a POSIX signal to the process. + * + * @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants) + * @param bool $throwException Whether to throw exception in case signal failed + * + * @return bool True if the signal was sent successfully, false otherwise + * + * @throws LogicException In case the process is not running + * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed + * @throws RuntimeException In case of failure + */ + private function doSignal($signal, $throwException) + { + if (!\is_int($signal)) { + if (!(\is_bool($signal) || \is_numeric($signal))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($signal) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($signal) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $signal = (int) $signal; + } + } + if (!\is_bool($throwException)) { + if (!(\is_bool($throwException) || \is_numeric($throwException) || \is_string($throwException))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($throwException) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($throwException) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $throwException = (bool) $throwException; + } + } + if (null === ($pid = $this->getPid())) { + if ($throwException) { + throw new LogicException('Can not send signal on a non running process.'); + } + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if ('\\' === \DIRECTORY_SEPARATOR) { + \exec(\sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode); + if ($exitCode && $this->isRunning()) { + if ($throwException) { + throw new RuntimeException(\sprintf('Unable to kill the process (%s).', \implode(' ', $output))); + } + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + } else { + if (!$this->isSigchildEnabled()) { + $ok = @\proc_terminate($this->process, $signal); + } elseif (\function_exists('posix_kill')) { + $ok = @\posix_kill($pid, $signal); + } elseif ($ok = \proc_open(\sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) { + $ok = \false === \fgets($pipes[2]); + } + if (!$ok) { + if ($throwException) { + throw new RuntimeException(\sprintf('Error while sending signal "%s".', $signal)); + } + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + } + $this->latestSignal = $signal; + $this->fallbackStatus['signaled'] = \true; + $this->fallbackStatus['exitcode'] = -1; + $this->fallbackStatus['termsig'] = $this->latestSignal; + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + private function prepareWindowsCommandLine($cmd, array &$env) + { + if (!\is_string($cmd)) { + if (!(\is_string($cmd) || \is_object($cmd) && \method_exists($cmd, '__toString') || (\is_bool($cmd) || \is_numeric($cmd)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($cmd) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cmd) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cmd = (string) $cmd; + } + } + $uid = \uniqid('', \true); + $varCount = 0; + $varCache = []; + $cmd = \preg_replace_callback('/"(?:( + [^"%!^]*+ + (?: + (?: !LF! | "(?:\\^[%!^])?+" ) + [^"%!^]*+ + )++ + ) | [^"]*+ )"/x', function ($m) use(&$env, &$varCache, &$varCount, $uid) { + if (!isset($m[1])) { + return $m[0]; + } + if (isset($varCache[$m[0]])) { + return $varCache[$m[0]]; + } + if (\str_contains($value = $m[1], "\x00")) { + $value = \str_replace("\x00", '?', $value); + } + if (\false === \strpbrk($value, "\"%!\n")) { + return '"' . $value . '"'; + } + $value = \str_replace(['!LF!', '"^!"', '"^%"', '"^^"', '""'], ["\n", '!', '%', '^', '"'], $value); + $value = '"' . \preg_replace('/(\\\\*)"/', '$1$1\\"', $value) . '"'; + $var = $uid . ++$varCount; + $env[$var] = $value; + return $varCache[$m[0]] = '!' . $var . '!'; + }, $cmd); + $cmd = 'cmd /V:ON /E:ON /D /C (' . \str_replace("\n", ' ', $cmd) . ')'; + foreach ($this->processPipes->getFiles() as $offset => $filename) { + $cmd .= ' ' . $offset . '>"' . $filename . '"'; + } + $phabelReturn = $cmd; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Ensures the process is running or terminated, throws a LogicException if the process has a not started. + * + * @throws LogicException if the process has not run + */ + private function requireProcessIsStarted($functionName) + { + if (!\is_string($functionName)) { + if (!(\is_string($functionName) || \is_object($functionName) && \method_exists($functionName, '__toString') || (\is_bool($functionName) || \is_numeric($functionName)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($functionName) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($functionName) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $functionName = (string) $functionName; + } + } + if (!$this->isStarted()) { + throw new LogicException(\sprintf('Process must be started before calling "%s()".', $functionName)); + } + } + /** + * Ensures the process is terminated, throws a LogicException if the process has a status different than "terminated". + * + * @throws LogicException if the process is not yet terminated + */ + private function requireProcessIsTerminated($functionName) + { + if (!\is_string($functionName)) { + if (!(\is_string($functionName) || \is_object($functionName) && \method_exists($functionName, '__toString') || (\is_bool($functionName) || \is_numeric($functionName)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($functionName) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($functionName) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $functionName = (string) $functionName; + } + } + if (!$this->isTerminated()) { + throw new LogicException(\sprintf('Process must be terminated before calling "%s()".', $functionName)); + } + } + /** + * Escapes a string to be used as a shell argument. + */ + private function escapeArgument($argument) + { + if (!\is_null($argument)) { + if (!\is_string($argument)) { + if (!(\is_string($argument) || \is_object($argument) && \method_exists($argument, '__toString') || (\is_bool($argument) || \is_numeric($argument)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($argument) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($argument) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $argument = (string) $argument; + } + } + } + if ('' === $argument || null === $argument) { + $phabelReturn = '""'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if ('\\' !== \DIRECTORY_SEPARATOR) { + $phabelReturn = "'" . \str_replace("'", "'\\''", $argument) . "'"; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (\str_contains($argument, "\x00")) { + $argument = \str_replace("\x00", '?', $argument); + } + if (!\preg_match('/[\\/()%!^"<>&|\\s]/', $argument)) { + $phabelReturn = $argument; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $argument = \preg_replace('/(\\\\+)$/', '$1$1', $argument); + $phabelReturn = '"' . \str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument) . '"'; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + private function replacePlaceholders($commandline, array $env) + { + if (!\is_string($commandline)) { + if (!(\is_string($commandline) || \is_object($commandline) && \method_exists($commandline, '__toString') || (\is_bool($commandline) || \is_numeric($commandline)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($commandline) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($commandline) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $commandline = (string) $commandline; + } + } + return \preg_replace_callback('/"\\$\\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\\}"/', function ($matches) use($commandline, $env) { + if (!isset($env[$matches[1]]) || \false === $env[$matches[1]]) { + throw new InvalidArgumentException(\sprintf('Command line is missing a value for parameter "%s": ', $matches[1]) . $commandline); + } + return $this->escapeArgument($env[$matches[1]]); + }, $commandline); + } + private function getDefaultEnv() + { + $env = []; + foreach ($_SERVER as $k => $v) { + if (\is_string($v) && \false !== ($v = \getenv($k))) { + $env[$k] = $v; + } + } + foreach ($_ENV as $k => $v) { + if (\is_string($v)) { + $env[$k] = $v; + } + } + $phabelReturn = $env; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/process/ProcessUtils.php b/vendor-bundle/symfony/process/ProcessUtils.php new file mode 100644 index 000000000..54c633372 --- /dev/null +++ b/vendor-bundle/symfony/process/ProcessUtils.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\Process; + +use Phabel\Symfony\Component\Process\Exception\InvalidArgumentException; +/** + * ProcessUtils is a bunch of utility methods. + * + * This class contains static methods only and is not meant to be instantiated. + * + * @author Martin Hasoň + */ +class ProcessUtils +{ + /** + * This class should not be instantiated. + */ + private function __construct() + { + } + /** + * Validates and normalizes a Process input. + * + * @param string $caller The name of method call that validates the input + * @param mixed $input The input to validate + * + * @return mixed The validated input + * + * @throws InvalidArgumentException In case the input is not valid + */ + public static function validateInput($caller, $input) + { + if (!\is_string($caller)) { + if (!(\is_string($caller) || \is_object($caller) && \method_exists($caller, '__toString') || (\is_bool($caller) || \is_numeric($caller)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($caller) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($caller) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $caller = (string) $caller; + } + } + if (null !== $input) { + if (\is_resource($input)) { + return $input; + } + if (\is_string($input)) { + return $input; + } + if (\is_scalar($input)) { + return (string) $input; + } + if ($input instanceof Process) { + return $input->getIterator($input::ITER_SKIP_ERR); + } + if ($input instanceof \Iterator) { + return $input; + } + if ($input instanceof \Traversable) { + return new \IteratorIterator($input); + } + throw new InvalidArgumentException(\sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller)); + } + return $input; + } +} diff --git a/vendor-bundle/symfony/service-contracts/Attribute/Required.php b/vendor-bundle/symfony/service-contracts/Attribute/Required.php new file mode 100644 index 000000000..7f514e97d --- /dev/null +++ b/vendor-bundle/symfony/service-contracts/Attribute/Required.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Contracts\Service\Attribute; + +/** + * A required dependency. + * + * This attribute indicates that a property holds a required dependency. The annotated property or method should be + * considered during the instantiation process of the containing class. + * + * @author Alexander M. Turek + */ +#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] +final class Required +{ +} diff --git a/vendor-bundle/symfony/service-contracts/ResetInterface.php b/vendor-bundle/symfony/service-contracts/ResetInterface.php new file mode 100644 index 000000000..e8387be62 --- /dev/null +++ b/vendor-bundle/symfony/service-contracts/ResetInterface.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Contracts\Service; + +/** + * Provides a way to reset an object to its initial state. + * + * When calling the "reset()" method on an object, it should be put back to its + * initial state. This usually means clearing any internal buffers and forwarding + * the call to internal dependencies. All properties of the object should be put + * back to the same state it had when it was first ready to use. + * + * This method could be called, for example, to recycle objects that are used as + * services, so that they can be used to handle several requests in the same + * process loop (note that we advise making your services stateless instead of + * implementing this interface when possible.) + */ +interface ResetInterface +{ + public function reset(); +} diff --git a/vendor-bundle/symfony/service-contracts/ServiceLocatorTrait.php b/vendor-bundle/symfony/service-contracts/ServiceLocatorTrait.php new file mode 100644 index 000000000..ab93585a3 --- /dev/null +++ b/vendor-bundle/symfony/service-contracts/ServiceLocatorTrait.php @@ -0,0 +1,167 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Contracts\Service; + +use Phabel\Psr\Container\ContainerExceptionInterface; +use Phabel\Psr\Container\NotFoundExceptionInterface; +// Help opcache.preload discover always-needed symbols +\class_exists(ContainerExceptionInterface::class); +\class_exists(NotFoundExceptionInterface::class); +/** + * A trait to help implement ServiceProviderInterface. + * + * @author Robin Chalas + * @author Nicolas Grekas + */ +trait ServiceLocatorTrait +{ + private $factories; + private $loading = []; + private $providedTypes; + /** + * @param callable[] $factories + */ + public function __construct(array $factories) + { + $this->factories = $factories; + } + /** + * {@inheritdoc} + * + * @return bool + */ + public function has($id) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + return isset($this->factories[$id]); + } + /** + * {@inheritdoc} + * + * @return mixed + */ + public function get($id) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + if (!isset($this->factories[$id])) { + throw $this->createNotFoundException($id); + } + if (isset($this->loading[$id])) { + $ids = \array_values($this->loading); + $ids = \array_slice($this->loading, \array_search($id, $ids)); + $ids[] = $id; + throw $this->createCircularReferenceException($id, $ids); + } + $this->loading[$id] = $id; + try { + return $this->factories[$id]($this); + } finally { + unset($this->loading[$id]); + } + } + /** + * {@inheritdoc} + */ + public function getProvidedServices() + { + if (null === $this->providedTypes) { + $this->providedTypes = []; + foreach ($this->factories as $name => $factory) { + if (!\is_callable($factory)) { + $this->providedTypes[$name] = '?'; + } else { + $type = (new \ReflectionFunction($factory))->getReturnType(); + $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '') . ($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?'; + } + } + } + $phabelReturn = $this->providedTypes; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function createNotFoundException($id) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + if (!($alternatives = \array_keys($this->factories))) { + $message = 'is empty...'; + } else { + $last = \array_pop($alternatives); + if ($alternatives) { + $message = \sprintf('only knows about the "%s" and "%s" services.', \implode('", "', $alternatives), $last); + } else { + $message = \sprintf('only knows about the "%s" service.', $last); + } + } + if ($this->loading) { + $message = \sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', \end($this->loading), $id, $message); + } else { + $message = \sprintf('Service "%s" not found: the current service locator %s', $id, $message); + } + if (!\class_exists(PhabelAnonymousClass15ed802adcadd91f17e793c43a12bd8830bcfabce3d3783b2ee9f7aa6a139dfc7::class)) { + class PhabelAnonymousClass15ed802adcadd91f17e793c43a12bd8830bcfabce3d3783b2ee9f7aa6a139dfc7 extends \InvalidArgumentException implements NotFoundExceptionInterface, \Phabel\Target\Php70\AnonymousClass\AnonymousClassInterface + { + public static function getPhabelOriginalName() + { + return \InvalidArgumentException::class . '@anonymous'; + } + } + } + $phabelReturn = new PhabelAnonymousClass15ed802adcadd91f17e793c43a12bd8830bcfabce3d3783b2ee9f7aa6a139dfc7($message); + if (!$phabelReturn instanceof NotFoundExceptionInterface) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type NotFoundExceptionInterface, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function createCircularReferenceException($id, array $path) + { + if (!\is_string($id)) { + if (!(\is_string($id) || \is_object($id) && \method_exists($id, '__toString') || (\is_bool($id) || \is_numeric($id)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($id) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($id) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $id = (string) $id; + } + } + if (!\class_exists(PhabelAnonymousClass15ed802adcadd91f17e793c43a12bd8830bcfabce3d3783b2ee9f7aa6a139dfc8::class)) { + class PhabelAnonymousClass15ed802adcadd91f17e793c43a12bd8830bcfabce3d3783b2ee9f7aa6a139dfc8 extends \RuntimeException implements ContainerExceptionInterface, \Phabel\Target\Php70\AnonymousClass\AnonymousClassInterface + { + public static function getPhabelOriginalName() + { + return \RuntimeException::class . '@anonymous'; + } + } + } + $phabelReturn = new PhabelAnonymousClass15ed802adcadd91f17e793c43a12bd8830bcfabce3d3783b2ee9f7aa6a139dfc8(\sprintf('Circular reference detected for service "%s", path: "%s".', $id, \implode(' -> ', $path))); + if (!$phabelReturn instanceof ContainerExceptionInterface) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ContainerExceptionInterface, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/service-contracts/ServiceProviderInterface.php b/vendor-bundle/symfony/service-contracts/ServiceProviderInterface.php new file mode 100644 index 000000000..88c87f3f9 --- /dev/null +++ b/vendor-bundle/symfony/service-contracts/ServiceProviderInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Contracts\Service; + +use Phabel\Psr\Container\ContainerInterface; +/** + * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container. + * + * @author Nicolas Grekas + * @author Mateusz Sip + */ +interface ServiceProviderInterface extends ContainerInterface +{ + /** + * Returns an associative array of service types keyed by the identifiers provided by the current container. + * + * Examples: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface + * * ['foo' => '?'] means the container provides service name "foo" of unspecified type + * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null + * + * @return string[] The provided service types, keyed by service names + */ + public function getProvidedServices(); +} diff --git a/vendor-bundle/symfony/service-contracts/ServiceSubscriberInterface.php b/vendor-bundle/symfony/service-contracts/ServiceSubscriberInterface.php new file mode 100644 index 000000000..0c9e36dda --- /dev/null +++ b/vendor-bundle/symfony/service-contracts/ServiceSubscriberInterface.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Contracts\Service; + +/** + * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method. + * + * The getSubscribedServices method returns an array of service types required by such instances, + * optionally keyed by the service names used internally. Service types that start with an interrogation + * mark "?" are optional, while the other ones are mandatory service dependencies. + * + * The injected service locators SHOULD NOT allow access to any other services not specified by the method. + * + * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally. + * This interface does not dictate any injection method for these service locators, although constructor + * injection is recommended. + * + * @author Nicolas Grekas + */ +interface ServiceSubscriberInterface +{ + /** + * Returns an array of service types required by such instances, optionally keyed by the service names used internally. + * + * For mandatory dependencies: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name + * internally to fetch a service which must implement Psr\Log\LoggerInterface. + * * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name + * internally to fetch an iterable of Psr\Log\LoggerInterface instances. + * * ['Psr\Log\LoggerInterface'] is a shortcut for + * * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface'] + * + * otherwise: + * + * * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency + * * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency + * * ['?Psr\Log\LoggerInterface'] is a shortcut for + * * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface'] + * + * @return string[] The required service types, optionally keyed by service names + */ + public static function getSubscribedServices(); +} diff --git a/vendor-bundle/symfony/service-contracts/ServiceSubscriberTrait.php b/vendor-bundle/symfony/service-contracts/ServiceSubscriberTrait.php new file mode 100644 index 000000000..c993d6e1c --- /dev/null +++ b/vendor-bundle/symfony/service-contracts/ServiceSubscriberTrait.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Contracts\Service; + +use Phabel\Psr\Container\ContainerInterface; +/** + * Implementation of ServiceSubscriberInterface that determines subscribed services from + * private method return types. Service ids are available as "ClassName::methodName". + * + * @author Kevin Bond + */ +trait ServiceSubscriberTrait +{ + /** @var ContainerInterface */ + protected $container; + /** + * {@inheritdoc} + */ + public static function getSubscribedServices() + { + static $services; + if (null !== $services) { + $phabelReturn = $services; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $services = \is_callable(['parent', __FUNCTION__]) ? parent::getSubscribedServices() : []; + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + continue; + } + if (self::class === $method->getDeclaringClass()->name && ($returnType = $method->getReturnType()) && !$returnType->isBuiltin()) { + $services[self::class . '::' . $method->name] = '?' . ($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType); + } + } + $phabelReturn = $services; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @required + */ + public function setContainer(ContainerInterface $container) + { + $this->container = $container; + if (\is_callable(['parent', __FUNCTION__])) { + return parent::setContainer($container); + } + return null; + } +} diff --git a/vendor-bundle/symfony/service-contracts/Test/ServiceLocatorTest.php b/vendor-bundle/symfony/service-contracts/Test/ServiceLocatorTest.php new file mode 100644 index 000000000..dec9a7632 --- /dev/null +++ b/vendor-bundle/symfony/service-contracts/Test/ServiceLocatorTest.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Contracts\Service\Test; + +use Phabel\PHPUnit\Framework\TestCase; +use Phabel\Psr\Container\ContainerInterface; +use Phabel\Symfony\Contracts\Service\ServiceLocatorTrait; +abstract class ServiceLocatorTest extends TestCase +{ + protected function getServiceLocator(array $factories) + { + return new PhabelAnonymousClasse6eaac63c3d52a7d24fda0e4ab2c37f0aee58e7016fe8731356cc303e0d1d8826($factories); + } + public function testHas() + { + $locator = $this->getServiceLocator(['foo' => function () { + return 'bar'; + }, 'bar' => function () { + return 'baz'; + }, function () { + return 'dummy'; + }]); + $this->assertTrue($locator->has('foo')); + $this->assertTrue($locator->has('bar')); + $this->assertFalse($locator->has('dummy')); + } + public function testGet() + { + $locator = $this->getServiceLocator(['foo' => function () { + return 'bar'; + }, 'bar' => function () { + return 'baz'; + }]); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('baz', $locator->get('bar')); + } + public function testGetDoesNotMemoize() + { + $i = 0; + $locator = $this->getServiceLocator(['foo' => function () use(&$i) { + ++$i; + return 'bar'; + }]); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame(2, $i); + } + public function testThrowsOnUndefinedInternalService() + { + if (!$this->getExpectedException()) { + $this->expectException(\Phabel\Psr\Container\NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); + } + $locator = $this->getServiceLocator(['foo' => function () use(&$locator) { + return $locator->get('bar'); + }]); + $locator->get('foo'); + } + public function testThrowsOnCircularReference() + { + $this->expectException(\Phabel\Psr\Container\ContainerExceptionInterface::class); + $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); + $locator = $this->getServiceLocator(['foo' => function () use(&$locator) { + return $locator->get('bar'); + }, 'bar' => function () use(&$locator) { + return $locator->get('baz'); + }, 'baz' => function () use(&$locator) { + return $locator->get('bar'); + }]); + $locator->get('foo'); + } +} +if (!\class_exists(PhabelAnonymousClasse6eaac63c3d52a7d24fda0e4ab2c37f0aee58e7016fe8731356cc303e0d1d8826::class)) { + class PhabelAnonymousClasse6eaac63c3d52a7d24fda0e4ab2c37f0aee58e7016fe8731356cc303e0d1d8826 implements ContainerInterface, \Phabel\Target\Php70\AnonymousClass\AnonymousClassInterface + { + use ServiceLocatorTrait; + public static function getPhabelOriginalName() + { + return ContainerInterface::class . '@anonymous'; + } + } +} diff --git a/vendor-bundle/symfony/string/AbstractString.php b/vendor-bundle/symfony/string/AbstractString.php new file mode 100644 index 000000000..67a2cdaad --- /dev/null +++ b/vendor-bundle/symfony/string/AbstractString.php @@ -0,0 +1,989 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String; + +use Phabel\Symfony\Component\String\Exception\ExceptionInterface; +use Phabel\Symfony\Component\String\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\String\Exception\RuntimeException; +/** + * Represents a string of abstract characters. + * + * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters). + * This class is the abstract type to use as a type-hint when the logic you want to + * implement doesn't care about the exact variant it deals with. + * + * @author Nicolas Grekas + * @author Hugo Hamon + * + * @throws ExceptionInterface + */ +abstract class AbstractString implements \Stringable, \JsonSerializable +{ + const PREG_PATTERN_ORDER = \PREG_PATTERN_ORDER; + const PREG_SET_ORDER = \PREG_SET_ORDER; + const PREG_OFFSET_CAPTURE = \PREG_OFFSET_CAPTURE; + const PREG_UNMATCHED_AS_NULL = \PREG_UNMATCHED_AS_NULL; + const PREG_SPLIT = 0; + const PREG_SPLIT_NO_EMPTY = \PREG_SPLIT_NO_EMPTY; + const PREG_SPLIT_DELIM_CAPTURE = \PREG_SPLIT_DELIM_CAPTURE; + const PREG_SPLIT_OFFSET_CAPTURE = \PREG_SPLIT_OFFSET_CAPTURE; + protected $string = ''; + protected $ignoreCase = \false; + public abstract function __construct($string = ''); + /** + * Unwraps instances of AbstractString back to strings. + * + * @return string[]|array + */ + public static function unwrap(array $values) + { + foreach ($values as $k => $v) { + if ($v instanceof self) { + $values[$k] = $v->__toString(); + } elseif (\is_array($v) && $values[$k] !== ($v = static::unwrap($v))) { + $values[$k] = $v; + } + } + $phabelReturn = $values; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Wraps (and normalizes) strings in instances of AbstractString. + * + * @return static[]|array + */ + public static function wrap(array $values) + { + $i = 0; + $keys = null; + foreach ($values as $k => $v) { + if (\is_string($k) && '' !== $k && $k !== ($j = (string) new static($k))) { + $keys = isset($keys) ? $keys : \array_keys($values); + $keys[$i] = $j; + } + if (\is_string($v)) { + $values[$k] = new static($v); + } elseif (\is_array($v) && $values[$k] !== ($v = static::wrap($v))) { + $values[$k] = $v; + } + ++$i; + } + $phabelReturn = null !== $keys ? \array_combine($keys, $values) : $values; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string|string[] $needle + * + * @return static + */ + public function after($needle, $includeNeedle = \false, $offset = 0) + { + if (!\is_bool($includeNeedle)) { + if (!(\is_bool($includeNeedle) || \is_numeric($includeNeedle) || \is_string($includeNeedle))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($includeNeedle) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($includeNeedle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $includeNeedle = (bool) $includeNeedle; + } + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + $str = clone $this; + $i = \PHP_INT_MAX; + foreach ((array) $needle as $n) { + $n = (string) $n; + $j = $this->indexOf($n, $offset); + if (null !== $j && $j < $i) { + $i = $j; + $str->string = $n; + } + } + if (\PHP_INT_MAX === $i) { + $phabelReturn = $str; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if (!$includeNeedle) { + $i += $str->length(); + } + $phabelReturn = $this->slice($i); + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string|string[] $needle + * + * @return static + */ + public function afterLast($needle, $includeNeedle = \false, $offset = 0) + { + if (!\is_bool($includeNeedle)) { + if (!(\is_bool($includeNeedle) || \is_numeric($includeNeedle) || \is_string($includeNeedle))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($includeNeedle) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($includeNeedle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $includeNeedle = (bool) $includeNeedle; + } + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + $str = clone $this; + $i = null; + foreach ((array) $needle as $n) { + $n = (string) $n; + $j = $this->indexOfLast($n, $offset); + if (null !== $j && $j >= $i) { + $i = $offset = $j; + $str->string = $n; + } + } + if (null === $i) { + $phabelReturn = $str; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if (!$includeNeedle) { + $i += $str->length(); + } + $phabelReturn = $this->slice($i); + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return static + */ + public abstract function append(...$suffix); + /** + * @param string|string[] $needle + * + * @return static + */ + public function before($needle, $includeNeedle = \false, $offset = 0) + { + if (!\is_bool($includeNeedle)) { + if (!(\is_bool($includeNeedle) || \is_numeric($includeNeedle) || \is_string($includeNeedle))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($includeNeedle) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($includeNeedle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $includeNeedle = (bool) $includeNeedle; + } + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + $str = clone $this; + $i = \PHP_INT_MAX; + foreach ((array) $needle as $n) { + $n = (string) $n; + $j = $this->indexOf($n, $offset); + if (null !== $j && $j < $i) { + $i = $j; + $str->string = $n; + } + } + if (\PHP_INT_MAX === $i) { + $phabelReturn = $str; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($includeNeedle) { + $i += $str->length(); + } + $phabelReturn = $this->slice(0, $i); + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string|string[] $needle + * + * @return static + */ + public function beforeLast($needle, $includeNeedle = \false, $offset = 0) + { + if (!\is_bool($includeNeedle)) { + if (!(\is_bool($includeNeedle) || \is_numeric($includeNeedle) || \is_string($includeNeedle))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($includeNeedle) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($includeNeedle) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $includeNeedle = (bool) $includeNeedle; + } + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + $str = clone $this; + $i = null; + foreach ((array) $needle as $n) { + $n = (string) $n; + $j = $this->indexOfLast($n, $offset); + if (null !== $j && $j >= $i) { + $i = $offset = $j; + $str->string = $n; + } + } + if (null === $i) { + $phabelReturn = $str; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ($includeNeedle) { + $i += $str->length(); + } + $phabelReturn = $this->slice(0, $i); + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return int[] + */ + public function bytesAt($offset) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + $str = $this->slice($offset, 1); + $phabelReturn = '' === $str->string ? [] : \array_values(\unpack('C*', $str->string)); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return static + */ + public abstract function camel(); + /** + * @return static[] + */ + public abstract function chunk($length = 1); + /** + * @return static + */ + public function collapseWhitespace() + { + $str = clone $this; + $str->string = \trim(\preg_replace('/(?:\\s{2,}+|[^\\S ])/', ' ', $str->string)); + $phabelReturn = $str; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string|string[] $needle + */ + public function containsAny($needle) + { + $phabelReturn = null !== $this->indexOf($needle); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @param string|string[] $suffix + */ + public function endsWith($suffix) + { + if (!\is_array($suffix) && !$suffix instanceof \Traversable) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + foreach ($suffix as $s) { + if ($this->endsWith((string) $s)) { + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + } + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return static + */ + public function ensureEnd($suffix) + { + if (!\is_string($suffix)) { + if (!(\is_string($suffix) || \is_object($suffix) && \method_exists($suffix, '__toString') || (\is_bool($suffix) || \is_numeric($suffix)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($suffix) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($suffix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $suffix = (string) $suffix; + } + } + if (!$this->endsWith($suffix)) { + $phabelReturn = $this->append($suffix); + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $suffix = \preg_quote($suffix); + $regex = '{(' . $suffix . ')(?:' . $suffix . ')++$}D'; + $phabelReturn = $this->replaceMatches($regex . ($this->ignoreCase ? 'i' : ''), '$1'); + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return static + */ + public function ensureStart($prefix) + { + if (!\is_string($prefix)) { + if (!(\is_string($prefix) || \is_object($prefix) && \method_exists($prefix, '__toString') || (\is_bool($prefix) || \is_numeric($prefix)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($prefix) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($prefix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $prefix = (string) $prefix; + } + } + $prefix = new static($prefix); + if (!$this->startsWith($prefix)) { + $phabelReturn = $this->prepend($prefix); + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $str = clone $this; + $i = $prefixLen = $prefix->length(); + while ($this->indexOf($prefix, $i) === $i) { + $str = $str->slice($prefixLen); + $i += $prefixLen; + } + $phabelReturn = $str; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string|string[] $string + */ + public function equalsTo($string) + { + if (!\is_array($string) && !$string instanceof \Traversable) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + foreach ($string as $s) { + if ($this->equalsTo((string) $s)) { + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + } + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return static + */ + public abstract function folded(); + /** + * @return static + */ + public function ignoreCase() + { + $str = clone $this; + $str->ignoreCase = \true; + $phabelReturn = $str; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string|string[] $needle + */ + public function indexOf($needle, $offset = 0) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + if (!\is_array($needle) && !$needle instanceof \Traversable) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + $i = \PHP_INT_MAX; + foreach ($needle as $n) { + $j = $this->indexOf((string) $n, $offset); + if (null !== $j && $j < $i) { + $i = $j; + } + } + $phabelReturn = \PHP_INT_MAX === $i ? null : $i; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + /** + * @param string|string[] $needle + */ + public function indexOfLast($needle, $offset = 0) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + if (!\is_array($needle) && !$needle instanceof \Traversable) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + $i = null; + foreach ($needle as $n) { + $j = $this->indexOfLast((string) $n, $offset); + if (null !== $j && $j >= $i) { + $i = $offset = $j; + } + } + $phabelReturn = $i; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + public function isEmpty() + { + $phabelReturn = '' === $this->string; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return static + */ + public abstract function join(array $strings, $lastGlue = null); + public function jsonSerialize() + { + $phabelReturn = $this->string; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public abstract function length(); + /** + * @return static + */ + public abstract function lower(); + /** + * Matches the string using a regular expression. + * + * Pass PREG_PATTERN_ORDER or PREG_SET_ORDER as $flags to get all occurrences matching the regular expression. + * + * @return array All matches in a multi-dimensional array ordered according to flags + */ + public abstract function match($regexp, $flags = 0, $offset = 0); + /** + * @return static + */ + public abstract function padBoth($length, $padStr = ' '); + /** + * @return static + */ + public abstract function padEnd($length, $padStr = ' '); + /** + * @return static + */ + public abstract function padStart($length, $padStr = ' '); + /** + * @return static + */ + public abstract function prepend(...$prefix); + /** + * @return static + */ + public function repeat($multiplier) + { + if (!\is_int($multiplier)) { + if (!(\is_bool($multiplier) || \is_numeric($multiplier))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($multiplier) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($multiplier) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $multiplier = (int) $multiplier; + } + } + if (0 > $multiplier) { + throw new InvalidArgumentException(\sprintf('Multiplier must be positive, %d given.', $multiplier)); + } + $str = clone $this; + $str->string = \str_repeat($str->string, $multiplier); + $phabelReturn = $str; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return static + */ + public abstract function replace($from, $to); + /** + * @param string|callable $to + * + * @return static + */ + public abstract function replaceMatches($fromRegexp, $to); + /** + * @return static + */ + public abstract function reverse(); + /** + * @return static + */ + public abstract function slice($start = 0, $length = null); + /** + * @return static + */ + public abstract function snake(); + /** + * @return static + */ + public abstract function splice($replacement, $start = 0, $length = null); + /** + * @return static[] + */ + public function split($delimiter, $limit = null, $flags = null) + { + if (!\is_string($delimiter)) { + if (!(\is_string($delimiter) || \is_object($delimiter) && \method_exists($delimiter, '__toString') || (\is_bool($delimiter) || \is_numeric($delimiter)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($delimiter) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($delimiter) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $delimiter = (string) $delimiter; + } + } + if (!\is_null($limit)) { + if (!\is_int($limit)) { + if (!(\is_bool($limit) || \is_numeric($limit))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($limit) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($limit) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $limit = (int) $limit; + } + } + } + if (!\is_null($flags)) { + if (!\is_int($flags)) { + if (!(\is_bool($flags) || \is_numeric($flags))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($flags) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($flags) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $flags = (int) $flags; + } + } + } + if (null === $flags) { + throw new \TypeError('Split behavior when $flags is null must be implemented by child classes.'); + } + if ($this->ignoreCase) { + $delimiter .= 'i'; + } + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + if (\false === ($chunks = \preg_split($delimiter, $this->string, $limit, $flags))) { + $lastError = \preg_last_error(); + foreach (\get_defined_constants(\true)['pcre'] as $k => $v) { + if ($lastError === $v && '_ERROR' === \substr($k, -6)) { + throw new RuntimeException('Splitting failed with ' . $k . '.'); + } + } + throw new RuntimeException('Splitting failed with unknown error code.'); + } + } finally { + \restore_error_handler(); + } + $str = clone $this; + if (self::PREG_SPLIT_OFFSET_CAPTURE & $flags) { + foreach ($chunks as &$chunk) { + $str->string = $chunk[0]; + $chunk[0] = clone $str; + } + } else { + foreach ($chunks as &$chunk) { + $str->string = $chunk; + $chunk = clone $str; + } + } + $phabelReturn = $chunks; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string|string[] $prefix + */ + public function startsWith($prefix) + { + if (!\is_array($prefix) && !$prefix instanceof \Traversable) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + foreach ($prefix as $prefix) { + if ($this->startsWith((string) $prefix)) { + $phabelReturn = \true; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + } + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return static + */ + public abstract function title($allWords = \false); + public function toByteString($toEncoding = null) + { + if (!\is_null($toEncoding)) { + if (!\is_string($toEncoding)) { + if (!(\is_string($toEncoding) || \is_object($toEncoding) && \method_exists($toEncoding, '__toString') || (\is_bool($toEncoding) || \is_numeric($toEncoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($toEncoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($toEncoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $toEncoding = (string) $toEncoding; + } + } + } + $b = new ByteString(); + $toEncoding = \in_array($toEncoding, ['utf8', 'utf-8', 'UTF8'], \true) ? 'UTF-8' : $toEncoding; + if (null === $toEncoding || $toEncoding === ($fromEncoding = $this instanceof AbstractUnicodeString || \preg_match('//u', $b->string) ? 'UTF-8' : 'Windows-1252')) { + $b->string = $this->string; + $phabelReturn = $b; + if (!$phabelReturn instanceof ByteString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ByteString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + try { + $b->string = \mb_convert_encoding($this->string, $toEncoding, 'UTF-8'); + } catch (InvalidArgumentException $e) { + if (!\function_exists('iconv')) { + throw $e; + } + $b->string = \iconv('UTF-8', $toEncoding, $this->string); + } + } finally { + \restore_error_handler(); + } + $phabelReturn = $b; + if (!$phabelReturn instanceof ByteString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ByteString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function toCodePointString() + { + $phabelReturn = new CodePointString($this->string); + if (!$phabelReturn instanceof CodePointString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type CodePointString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function toString() + { + $phabelReturn = $this->string; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + public function toUnicodeString() + { + $phabelReturn = new UnicodeString($this->string); + if (!$phabelReturn instanceof UnicodeString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type UnicodeString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return static + */ + public abstract function trim($chars = " \t\n\r\x00\v\f "); + /** + * @return static + */ + public abstract function trimEnd($chars = " \t\n\r\x00\v\f "); + /** + * @return static + */ + public abstract function trimStart($chars = " \t\n\r\x00\v\f "); + /** + * @return static + */ + public function truncate($length, $ellipsis = '', $cut = \true) + { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + if (!\is_string($ellipsis)) { + if (!(\is_string($ellipsis) || \is_object($ellipsis) && \method_exists($ellipsis, '__toString') || (\is_bool($ellipsis) || \is_numeric($ellipsis)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($ellipsis) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($ellipsis) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $ellipsis = (string) $ellipsis; + } + } + if (!\is_bool($cut)) { + if (!(\is_bool($cut) || \is_numeric($cut) || \is_string($cut))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($cut) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cut) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cut = (bool) $cut; + } + } + $stringLength = $this->length(); + if ($stringLength <= $length) { + $phabelReturn = clone $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $ellipsisLength = '' !== $ellipsis ? (new static($ellipsis))->length() : 0; + if ($length < $ellipsisLength) { + $ellipsisLength = 0; + } + if (!$cut) { + if (null === ($length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1))) { + $phabelReturn = clone $this; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $length += $ellipsisLength; + } + $str = $this->slice(0, $length - $ellipsisLength); + $phabelReturn = $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return static + */ + public abstract function upper(); + /** + * Returns the printable length on a terminal. + */ + public abstract function width($ignoreAnsiDecoration = \true); + /** + * @return static + */ + public function wordwrap($width = 75, $break = "\n", $cut = \false) + { + if (!\is_int($width)) { + if (!(\is_bool($width) || \is_numeric($width))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($width) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($width) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $width = (int) $width; + } + } + if (!\is_string($break)) { + if (!(\is_string($break) || \is_object($break) && \method_exists($break, '__toString') || (\is_bool($break) || \is_numeric($break)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($break) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($break) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $break = (string) $break; + } + } + if (!\is_bool($cut)) { + if (!(\is_bool($cut) || \is_numeric($cut) || \is_string($cut))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($cut) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($cut) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $cut = (bool) $cut; + } + } + $lines = '' !== $break ? $this->split($break) : [clone $this]; + $chars = []; + $mask = ''; + if (1 === \count($lines) && '' === $lines[0]->string) { + $phabelReturn = $lines[0]; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + foreach ($lines as $i => $line) { + if ($i) { + $chars[] = $break; + $mask .= '#'; + } + foreach ($line->chunk() as $char) { + $chars[] = $char->string; + $mask .= ' ' === $char->string ? ' ' : '?'; + } + } + $string = ''; + $j = 0; + $b = $i = -1; + $mask = \wordwrap($mask, $width, '#', $cut); + while (\false !== ($b = \strpos($mask, '#', $b + 1))) { + for (++$i; $i < $b; ++$i) { + $string .= $chars[$j]; + unset($chars[$j++]); + } + if ($break === $chars[$j] || ' ' === $chars[$j]) { + unset($chars[$j++]); + } + $string .= $break; + } + $str = clone $this; + $str->string = $string . \implode('', $chars); + $phabelReturn = $str; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function __sleep() + { + $phabelReturn = ['string']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function __clone() + { + $this->ignoreCase = \false; + } + public function __toString() + { + $phabelReturn = $this->string; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/string/AbstractUnicodeString.php b/vendor-bundle/symfony/string/AbstractUnicodeString.php new file mode 100644 index 000000000..032c4ed57 --- /dev/null +++ b/vendor-bundle/symfony/string/AbstractUnicodeString.php @@ -0,0 +1,763 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String; + +use Phabel\Symfony\Component\String\Exception\ExceptionInterface; +use Phabel\Symfony\Component\String\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\String\Exception\RuntimeException; +/** + * Represents a string of abstract Unicode characters. + * + * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters). + * This class is the abstract type to use as a type-hint when the logic you want to + * implement is Unicode-aware but doesn't care about code points vs grapheme clusters. + * + * @author Nicolas Grekas + * + * @throws ExceptionInterface + */ +abstract class AbstractUnicodeString extends AbstractString +{ + const NFC = \Normalizer::NFC; + const NFD = \Normalizer::NFD; + const NFKC = \Normalizer::NFKC; + const NFKD = \Normalizer::NFKD; + // all ASCII letters sorted by typical frequency of occurrence + const ASCII = " eiasntrolud][cmp'\ng|hv.fb,:=-q10C2*yx)(L9AS/P\"EjMIk3>5T>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))']; + private static $transliterators = []; + /** + * @return static + */ + public static function fromCodePoints(...$codes) + { + foreach ($codes as $phabelVariadicIndex => $phabelVariadic) { + if (!\is_int($phabelVariadic)) { + if (!(\is_bool($phabelVariadic) || \is_numeric($phabelVariadic))) { + throw new \TypeError(__METHOD__ . '(): Argument #' . (1 + $phabelVariadicIndex) . ' must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($codes) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelVariadic = (int) $phabelVariadic; + } + } + } + $string = ''; + foreach ($codes as $code) { + if (0x80 > ($code %= 0x200000)) { + $string .= \chr($code); + } elseif (0x800 > $code) { + $string .= \chr(0xc0 | $code >> 6) . \chr(0x80 | $code & 0x3f); + } elseif (0x10000 > $code) { + $string .= \chr(0xe0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f); + } else { + $string .= \chr(0xf0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3f) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f); + } + } + $phabelReturn = new static($string); + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Generic UTF-8 to ASCII transliteration. + * + * Install the intl extension for best results. + * + * @param string[]|\Transliterator[]|\Closure[] $rules See "*-Latin" rules from Transliterator::listIDs() + */ + public function ascii(array $rules = []) + { + $str = clone $this; + $s = $str->string; + $str->string = ''; + \array_unshift($rules, 'nfd'); + $rules[] = 'latin-ascii'; + if (\function_exists('transliterator_transliterate')) { + $rules[] = 'any-latin/bgn'; + } + $rules[] = 'nfkd'; + $rules[] = '[:nonspacing mark:] remove'; + while (\strlen($s) - 1 > ($i = \strspn($s, self::ASCII))) { + if (0 < --$i) { + $str->string .= \substr($s, 0, $i); + $s = \substr($s, $i); + } + if (!($rule = \array_shift($rules))) { + $rules = []; + // An empty rule interrupts the next ones + } + if ($rule instanceof \Transliterator) { + $s = $rule->transliterate($s); + } elseif ($rule instanceof \Closure) { + $s = $rule($s); + } elseif ($rule) { + if ('nfd' === ($rule = \strtolower($rule))) { + \normalizer_is_normalized($s, self::NFD) ?: ($s = \normalizer_normalize($s, self::NFD)); + } elseif ('nfkd' === $rule) { + \normalizer_is_normalized($s, self::NFKD) ?: ($s = \normalizer_normalize($s, self::NFKD)); + } elseif ('[:nonspacing mark:] remove' === $rule) { + $s = \preg_replace('/\\p{Mn}++/u', '', $s); + } elseif ('latin-ascii' === $rule) { + $s = \str_replace(self::TRANSLIT_FROM, self::TRANSLIT_TO, $s); + } elseif ('de-ascii' === $rule) { + $s = \preg_replace("/([AUO])̈(?=\\p{Ll})/u", '$1e', $s); + $s = \str_replace(["ä", "ö", "ü", "Ä", "Ö", "Ü"], ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], $s); + } elseif (\function_exists('transliterator_transliterate')) { + if (null === ($transliterator = isset(self::$transliterators[$rule]) ? self::$transliterators[$rule] : (self::$transliterators[$rule] = \Transliterator::create($rule)))) { + if ('any-latin/bgn' === $rule) { + $rule = 'any-latin'; + $transliterator = isset(self::$transliterators[$rule]) ? self::$transliterators[$rule] : (self::$transliterators[$rule] = \Transliterator::create($rule)); + } + if (null === $transliterator) { + throw new InvalidArgumentException(\sprintf('Unknown transliteration rule "%s".', $rule)); + } + self::$transliterators['any-latin/bgn'] = $transliterator; + } + $s = $transliterator->transliterate($s); + } + } elseif (!\function_exists('iconv')) { + $s = \preg_replace('/[^\\x00-\\x7F]/u', '?', $s); + } else { + $s = @\preg_replace_callback('/[^\\x00-\\x7F]/u', static function ($c) { + $c = (string) \iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]); + if ('' === $c && '' === \iconv('UTF-8', 'ASCII//TRANSLIT', '²')) { + throw new \LogicException(\sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class)); + } + return 1 < \strlen($c) ? \ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?'); + }, $s); + } + } + $str->string .= $s; + $phabelReturn = $str; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function camel() + { + $str = clone $this; + $str->string = \str_replace(' ', '', \preg_replace_callback('/\\b./u', static function ($m) use(&$i) { + return 1 === ++$i ? 'İ' === $m[0] ? 'i̇' : \mb_strtolower($m[0], 'UTF-8') : \mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); + }, \preg_replace('/[^\\pL0-9]++/u', ' ', $this->string))); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return int[] + */ + public function codePointsAt($offset) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + $str = $this->slice($offset, 1); + if ('' === $str->string) { + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $codePoints = []; + foreach (\preg_split('//u', $str->string, -1, \PREG_SPLIT_NO_EMPTY) as $c) { + $codePoints[] = \mb_ord($c, 'UTF-8'); + } + $phabelReturn = $codePoints; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function folded($compat = \true) + { + if (!\is_bool($compat)) { + if (!(\is_bool($compat) || \is_numeric($compat) || \is_string($compat))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($compat) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($compat) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $compat = (bool) $compat; + } + } + $str = clone $this; + if (!$compat || \PHP_VERSION_ID < 70300 || !\defined('Normalizer::NFKC_CF')) { + $str->string = \normalizer_normalize($str->string, $compat ? \Normalizer::NFKC : \Normalizer::NFC); + $str->string = \mb_strtolower(\str_replace(self::FOLD_FROM, self::FOLD_TO, $this->string), 'UTF-8'); + } else { + $str->string = \normalizer_normalize($str->string, \Normalizer::NFKC_CF); + } + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function join(array $strings, $lastGlue = null) + { + if (!\is_null($lastGlue)) { + if (!\is_string($lastGlue)) { + if (!(\is_string($lastGlue) || \is_object($lastGlue) && \method_exists($lastGlue, '__toString') || (\is_bool($lastGlue) || \is_numeric($lastGlue)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($lastGlue) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($lastGlue) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $lastGlue = (string) $lastGlue; + } + } + } + $str = clone $this; + $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue . \array_pop($strings) : ''; + $str->string = \implode($this->string, $strings) . $tail; + if (!\preg_match('//u', $str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function lower() + { + $str = clone $this; + $str->string = \mb_strtolower(\str_replace('İ', 'i̇', $str->string), 'UTF-8'); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function match($regexp, $flags = 0, $offset = 0) + { + if (!\is_string($regexp)) { + if (!(\is_string($regexp) || \is_object($regexp) && \method_exists($regexp, '__toString') || (\is_bool($regexp) || \is_numeric($regexp)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($regexp) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($regexp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $regexp = (string) $regexp; + } + } + if (!\is_int($flags)) { + if (!(\is_bool($flags) || \is_numeric($flags))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($flags) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($flags) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $flags = (int) $flags; + } + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + $match = (\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags ? 'preg_match_all' : 'preg_match'; + if ($this->ignoreCase) { + $regexp .= 'i'; + } + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + if (\false === $match($regexp . 'u', $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { + $lastError = \preg_last_error(); + foreach (\get_defined_constants(\true)['pcre'] as $k => $v) { + if ($lastError === $v && '_ERROR' === \substr($k, -6)) { + throw new RuntimeException('Matching failed with ' . $k . '.'); + } + } + throw new RuntimeException('Matching failed with unknown error code.'); + } + } finally { + \restore_error_handler(); + } + $phabelReturn = $matches; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @return static + */ + public function normalize($form = self::NFC) + { + if (!\is_int($form)) { + if (!(\is_bool($form) || \is_numeric($form))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($form) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($form) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $form = (int) $form; + } + } + if (!\in_array($form, [self::NFC, self::NFD, self::NFKC, self::NFKD])) { + throw new InvalidArgumentException('Unsupported normalization form.'); + } + $str = clone $this; + \normalizer_is_normalized($str->string, $form) ?: ($str->string = \normalizer_normalize($str->string, $form)); + $phabelReturn = $str; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function padBoth($length, $padStr = ' ') + { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + if (!\is_string($padStr)) { + if (!(\is_string($padStr) || \is_object($padStr) && \method_exists($padStr, '__toString') || (\is_bool($padStr) || \is_numeric($padStr)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($padStr) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($padStr) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $padStr = (string) $padStr; + } + } + if ('' === $padStr || !\preg_match('//u', $padStr)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $pad = clone $this; + $pad->string = $padStr; + $phabelReturn = $this->pad($length, $pad, \STR_PAD_BOTH); + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function padEnd($length, $padStr = ' ') + { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + if (!\is_string($padStr)) { + if (!(\is_string($padStr) || \is_object($padStr) && \method_exists($padStr, '__toString') || (\is_bool($padStr) || \is_numeric($padStr)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($padStr) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($padStr) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $padStr = (string) $padStr; + } + } + if ('' === $padStr || !\preg_match('//u', $padStr)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $pad = clone $this; + $pad->string = $padStr; + $phabelReturn = $this->pad($length, $pad, \STR_PAD_RIGHT); + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function padStart($length, $padStr = ' ') + { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + if (!\is_string($padStr)) { + if (!(\is_string($padStr) || \is_object($padStr) && \method_exists($padStr, '__toString') || (\is_bool($padStr) || \is_numeric($padStr)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($padStr) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($padStr) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $padStr = (string) $padStr; + } + } + if ('' === $padStr || !\preg_match('//u', $padStr)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $pad = clone $this; + $pad->string = $padStr; + $phabelReturn = $this->pad($length, $pad, \STR_PAD_LEFT); + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function replaceMatches($fromRegexp, $to) + { + if (!\is_string($fromRegexp)) { + if (!(\is_string($fromRegexp) || \is_object($fromRegexp) && \method_exists($fromRegexp, '__toString') || (\is_bool($fromRegexp) || \is_numeric($fromRegexp)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($fromRegexp) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($fromRegexp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $fromRegexp = (string) $fromRegexp; + } + } + if ($this->ignoreCase) { + $fromRegexp .= 'i'; + } + if (\is_array($to) || $to instanceof \Closure) { + if (!\is_callable($to)) { + throw new \TypeError(\sprintf('Argument 2 passed to "%s::replaceMatches()" must be callable, array given.', static::class)); + } + $replace = 'preg_replace_callback'; + $to = static function (array $m) use($to) { + $to = $to($m); + if ('' !== $to && (!\is_string($to) || !\preg_match('//u', $to))) { + throw new InvalidArgumentException('Replace callback must return a valid UTF-8 string.'); + } + $phabelReturn = $to; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + }; + } elseif ('' !== $to && !\preg_match('//u', $to)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } else { + $replace = 'preg_replace'; + } + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + if (null === ($string = $replace($fromRegexp . 'u', $to, $this->string))) { + $lastError = \preg_last_error(); + foreach (\get_defined_constants(\true)['pcre'] as $k => $v) { + if ($lastError === $v && '_ERROR' === \substr($k, -6)) { + throw new RuntimeException('Matching failed with ' . $k . '.'); + } + } + throw new RuntimeException('Matching failed with unknown error code.'); + } + } finally { + \restore_error_handler(); + } + $str = clone $this; + $str->string = $string; + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function reverse() + { + $str = clone $this; + $str->string = \implode('', \array_reverse(\preg_split('/(\\X)/u', $str->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY))); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function snake() + { + $str = $this->camel()->title(); + $str->string = \mb_strtolower(\preg_replace(['/(\\p{Lu}+)(\\p{Lu}\\p{Ll})/u', '/([\\p{Ll}0-9])(\\p{Lu})/u'], 'Phabel\\1_\\2', $str->string), 'UTF-8'); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function title($allWords = \false) + { + if (!\is_bool($allWords)) { + if (!(\is_bool($allWords) || \is_numeric($allWords) || \is_string($allWords))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($allWords) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($allWords) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $allWords = (bool) $allWords; + } + } + $str = clone $this; + $limit = $allWords ? -1 : 1; + $str->string = \preg_replace_callback('/\\b./u', static function (array $m) { + $phabelReturn = \mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + }, $str->string, $limit); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function trim($chars = " \t\n\r\x00\v\f ") + { + if (!\is_string($chars)) { + if (!(\is_string($chars) || \is_object($chars) && \method_exists($chars, '__toString') || (\is_bool($chars) || \is_numeric($chars)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($chars) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($chars) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $chars = (string) $chars; + } + } + if (" \t\n\r\x00\v\f " !== $chars && !\preg_match('//u', $chars)) { + throw new InvalidArgumentException('Invalid UTF-8 chars.'); + } + $chars = \preg_quote($chars); + $str = clone $this; + $str->string = \preg_replace("{^[{$chars}]++|[{$chars}]++\$}uD", '', $str->string); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function trimEnd($chars = " \t\n\r\x00\v\f ") + { + if (!\is_string($chars)) { + if (!(\is_string($chars) || \is_object($chars) && \method_exists($chars, '__toString') || (\is_bool($chars) || \is_numeric($chars)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($chars) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($chars) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $chars = (string) $chars; + } + } + if (" \t\n\r\x00\v\f " !== $chars && !\preg_match('//u', $chars)) { + throw new InvalidArgumentException('Invalid UTF-8 chars.'); + } + $chars = \preg_quote($chars); + $str = clone $this; + $str->string = \preg_replace("{[{$chars}]++\$}uD", '', $str->string); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function trimStart($chars = " \t\n\r\x00\v\f ") + { + if (!\is_string($chars)) { + if (!(\is_string($chars) || \is_object($chars) && \method_exists($chars, '__toString') || (\is_bool($chars) || \is_numeric($chars)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($chars) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($chars) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $chars = (string) $chars; + } + } + if (" \t\n\r\x00\v\f " !== $chars && !\preg_match('//u', $chars)) { + throw new InvalidArgumentException('Invalid UTF-8 chars.'); + } + $chars = \preg_quote($chars); + $str = clone $this; + $str->string = \preg_replace("{^[{$chars}]++}uD", '', $str->string); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function upper() + { + $str = clone $this; + $str->string = \mb_strtoupper($str->string, 'UTF-8'); + if (\PHP_VERSION_ID < 70300) { + $str->string = \str_replace(self::UPPER_FROM, self::UPPER_TO, $str->string); + } + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function width($ignoreAnsiDecoration = \true) + { + if (!\is_bool($ignoreAnsiDecoration)) { + if (!(\is_bool($ignoreAnsiDecoration) || \is_numeric($ignoreAnsiDecoration) || \is_string($ignoreAnsiDecoration))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($ignoreAnsiDecoration) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($ignoreAnsiDecoration) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $ignoreAnsiDecoration = (bool) $ignoreAnsiDecoration; + } + } + $width = 0; + $s = \str_replace(["\x00", "\x05", "\x07"], '', $this->string); + if (\false !== \strpos($s, "\r")) { + $s = \str_replace(["\r\n", "\r"], "\n", $s); + } + if (!$ignoreAnsiDecoration) { + $s = \preg_replace('/[\\p{Cc}\\x7F]++/u', '', $s); + } + foreach (\explode("\n", $s) as $s) { + if ($ignoreAnsiDecoration) { + $s = \preg_replace('/(?:\\x1B(?: + \\[ [\\x30-\\x3F]*+ [\\x20-\\x2F]*+ [0x40-\\x7E] + | [P\\]X^_] .*? \\x1B\\\\ + | [\\x41-\\x7E] + )|[\\p{Cc}\\x7F]++)/xu', '', $s); + } + // Non printable characters have been dropped, so wcswidth cannot logically return -1. + $width += $this->wcswidth($s); + } + $phabelReturn = $width; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return static + */ + private function pad($len, self $pad, $type) + { + if (!\is_int($len)) { + if (!(\is_bool($len) || \is_numeric($len))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($len) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($len) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $len = (int) $len; + } + } + if (!\is_int($type)) { + if (!(\is_bool($type) || \is_numeric($type))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($type) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($type) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $type = (int) $type; + } + } + $sLen = $this->length(); + if ($len <= $sLen) { + $phabelReturn = clone $this; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $padLen = $pad->length(); + $freeLen = $len - $sLen; + $len = $freeLen % $padLen; + switch ($type) { + case \STR_PAD_RIGHT: + $phabelReturn = $this->append(\str_repeat($pad->string, \intdiv($freeLen, $padLen)) . ($len ? $pad->slice(0, $len) : '')); + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + case \STR_PAD_LEFT: + $phabelReturn = $this->prepend(\str_repeat($pad->string, \intdiv($freeLen, $padLen)) . ($len ? $pad->slice(0, $len) : '')); + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + case \STR_PAD_BOTH: + $freeLen /= 2; + $rightLen = \ceil($freeLen); + $len = $rightLen % $padLen; + $str = $this->append(\str_repeat($pad->string, \intdiv($rightLen, $padLen)) . ($len ? $pad->slice(0, $len) : '')); + $leftLen = \floor($freeLen); + $len = $leftLen % $padLen; + $phabelReturn = $str->prepend(\str_repeat($pad->string, \intdiv($leftLen, $padLen)) . ($len ? $pad->slice(0, $len) : '')); + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + default: + throw new InvalidArgumentException('Invalid padding type.'); + } + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', none returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + /** + * Based on https://github.com/jquast/wcwidth, a Python implementation of https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c. + */ + private function wcswidth($string) + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + $width = 0; + foreach (\preg_split('//u', $string, -1, \PREG_SPLIT_NO_EMPTY) as $c) { + $codePoint = \mb_ord($c, 'UTF-8'); + if (0 === $codePoint || 0x34f === $codePoint || 0x200b <= $codePoint && 0x200f >= $codePoint || 0x2028 === $codePoint || 0x2029 === $codePoint || 0x202a <= $codePoint && 0x202e >= $codePoint || 0x2060 <= $codePoint && 0x2063 >= $codePoint) { + continue; + } + // Non printable characters + if (32 > $codePoint || 0x7f <= $codePoint && 0xa0 > $codePoint) { + $phabelReturn = -1; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + static $tableZero; + if (null === $tableZero) { + $tableZero = (require __DIR__ . '/Resources/data/wcswidth_table_zero.php'); + } + if ($codePoint >= $tableZero[0][0] && $codePoint <= $tableZero[$ubound = \count($tableZero) - 1][1]) { + $lbound = 0; + while ($ubound >= $lbound) { + $mid = \floor(($lbound + $ubound) / 2); + if ($codePoint > $tableZero[$mid][1]) { + $lbound = $mid + 1; + } elseif ($codePoint < $tableZero[$mid][0]) { + $ubound = $mid - 1; + } else { + continue 2; + } + } + } + static $tableWide; + if (null === $tableWide) { + $tableWide = (require __DIR__ . '/Resources/data/wcswidth_table_wide.php'); + } + if ($codePoint >= $tableWide[0][0] && $codePoint <= $tableWide[$ubound = \count($tableWide) - 1][1]) { + $lbound = 0; + while ($ubound >= $lbound) { + $mid = \floor(($lbound + $ubound) / 2); + if ($codePoint > $tableWide[$mid][1]) { + $lbound = $mid + 1; + } elseif ($codePoint < $tableWide[$mid][0]) { + $ubound = $mid - 1; + } else { + $width += 2; + continue 2; + } + } + } + ++$width; + } + $phabelReturn = $width; + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/string/ByteString.php b/vendor-bundle/symfony/string/ByteString.php new file mode 100644 index 000000000..d533f6da3 --- /dev/null +++ b/vendor-bundle/symfony/string/ByteString.php @@ -0,0 +1,945 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String; + +use Phabel\Symfony\Component\String\Exception\ExceptionInterface; +use Phabel\Symfony\Component\String\Exception\InvalidArgumentException; +use Phabel\Symfony\Component\String\Exception\RuntimeException; +/** + * Represents a binary-safe string of bytes. + * + * @author Nicolas Grekas + * @author Hugo Hamon + * + * @throws ExceptionInterface + */ +class ByteString extends AbstractString +{ + const ALPHABET_ALPHANUMERIC = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; + public function __construct($string = '') + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + $this->string = $string; + } + /* + * The following method was derived from code of the Hack Standard Library (v4.40 - 2020-05-03) + * + * https://github.com/hhvm/hsl/blob/80a42c02f036f72a42f0415e80d6b847f4bf62d5/src/random/private.php#L16 + * + * Code subject to the MIT license (https://github.com/hhvm/hsl/blob/master/LICENSE). + * + * Copyright (c) 2004-2020, Facebook, Inc. (https://www.facebook.com/) + */ + public static function fromRandom($length = 16, $alphabet = null) + { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + if (!\is_null($alphabet)) { + if (!\is_string($alphabet)) { + if (!(\is_string($alphabet) || \is_object($alphabet) && \method_exists($alphabet, '__toString') || (\is_bool($alphabet) || \is_numeric($alphabet)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($alphabet) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($alphabet) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $alphabet = (string) $alphabet; + } + } + } + if ($length <= 0) { + throw new InvalidArgumentException(\sprintf('A strictly positive length is expected, "%d" given.', $length)); + } + $alphabet = isset($alphabet) ? $alphabet : self::ALPHABET_ALPHANUMERIC; + $alphabetSize = \strlen($alphabet); + $bits = (int) \ceil(\log($alphabetSize, 2.0)); + if ($bits <= 0 || $bits > 56) { + throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.'); + } + $ret = ''; + while ($length > 0) { + $urandomLength = (int) \ceil(2 * $length * $bits / 8.0); + $data = \random_bytes($urandomLength); + $unpackedData = 0; + $unpackedBits = 0; + for ($i = 0; $i < $urandomLength && $length > 0; ++$i) { + // Unpack 8 bits + $unpackedData = $unpackedData << 8 | \ord($data[$i]); + $unpackedBits += 8; + // While we have enough bits to select a character from the alphabet, keep + // consuming the random data + for (; $unpackedBits >= $bits && $length > 0; $unpackedBits -= $bits) { + $index = $unpackedData & (1 << $bits) - 1; + $unpackedData >>= $bits; + // Unfortunately, the alphabet size is not necessarily a power of two. + // Worst case, it is 2^k + 1, which means we need (k+1) bits and we + // have around a 50% chance of missing as k gets larger + if ($index < $alphabetSize) { + $ret .= $alphabet[$index]; + --$length; + } + } + } + } + $phabelReturn = new static($ret); + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function bytesAt($offset) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + $str = isset($this->string[$offset]) ? $this->string[$offset] : ''; + $phabelReturn = '' === $str ? [] : [\ord($str)]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function append(...$suffix) + { + foreach ($suffix as $phabelVariadicIndex => $phabelVariadic) { + if (!\is_string($phabelVariadic)) { + if (!(\is_string($phabelVariadic) || \is_object($phabelVariadic) && \method_exists($phabelVariadic, '__toString') || (\is_bool($phabelVariadic) || \is_numeric($phabelVariadic)))) { + throw new \TypeError(__METHOD__ . '(): Argument #' . (1 + $phabelVariadicIndex) . ' must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($suffix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelVariadic = (string) $phabelVariadic; + } + } + } + $str = clone $this; + $str->string .= 1 >= \count($suffix) ? isset($suffix[0]) ? $suffix[0] : '' : \implode('', $suffix); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function camel() + { + $str = clone $this; + $str->string = \lcfirst(\str_replace(' ', '', \ucwords(\preg_replace('/[^a-zA-Z0-9\\x7f-\\xff]++/', ' ', $this->string)))); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function chunk($length = 1) + { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + if (1 > $length) { + throw new InvalidArgumentException('The chunk length must be greater than zero.'); + } + if ('' === $this->string) { + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $str = clone $this; + $chunks = []; + foreach (\str_split($this->string, $length) as $chunk) { + $str->string = $chunk; + $chunks[] = clone $str; + } + $phabelReturn = $chunks; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function endsWith($suffix) + { + if ($suffix instanceof parent) { + $suffix = $suffix->string; + } elseif (\is_array($suffix) || $suffix instanceof \Traversable) { + $phabelReturn = parent::endsWith($suffix); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } else { + $suffix = (string) $suffix; + } + $phabelReturn = '' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === \substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function equalsTo($string) + { + if ($string instanceof parent) { + $string = $string->string; + } elseif (\is_array($string) || $string instanceof \Traversable) { + $phabelReturn = parent::equalsTo($string); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } else { + $string = (string) $string; + } + if ('' !== $string && $this->ignoreCase) { + $phabelReturn = 0 === \strcasecmp($string, $this->string); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = $string === $this->string; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function folded() + { + $str = clone $this; + $str->string = \strtolower($str->string); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function indexOf($needle, $offset = 0) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + if ($needle instanceof parent) { + $needle = $needle->string; + } elseif (\is_array($needle) || $needle instanceof \Traversable) { + $phabelReturn = parent::indexOf($needle, $offset); + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } else { + $needle = (string) $needle; + } + if ('' === $needle) { + $phabelReturn = null; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + $i = $this->ignoreCase ? \stripos($this->string, $needle, $offset) : \strpos($this->string, $needle, $offset); + $phabelReturn = \false === $i ? null : $i; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + public function indexOfLast($needle, $offset = 0) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + if ($needle instanceof parent) { + $needle = $needle->string; + } elseif (\is_array($needle) || $needle instanceof \Traversable) { + $phabelReturn = parent::indexOfLast($needle, $offset); + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } else { + $needle = (string) $needle; + } + if ('' === $needle) { + $phabelReturn = null; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + $i = $this->ignoreCase ? \strripos($this->string, $needle, $offset) : \strrpos($this->string, $needle, $offset); + $phabelReturn = \false === $i ? null : $i; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + public function isUtf8() + { + $phabelReturn = '' === $this->string || \preg_match('//u', $this->string); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function join(array $strings, $lastGlue = null) + { + if (!\is_null($lastGlue)) { + if (!\is_string($lastGlue)) { + if (!(\is_string($lastGlue) || \is_object($lastGlue) && \method_exists($lastGlue, '__toString') || (\is_bool($lastGlue) || \is_numeric($lastGlue)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($lastGlue) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($lastGlue) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $lastGlue = (string) $lastGlue; + } + } + } + $str = clone $this; + $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue . \array_pop($strings) : ''; + $str->string = \implode($this->string, $strings) . $tail; + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function length() + { + $phabelReturn = \strlen($this->string); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + public function lower() + { + $str = clone $this; + $str->string = \strtolower($str->string); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function match($regexp, $flags = 0, $offset = 0) + { + if (!\is_string($regexp)) { + if (!(\is_string($regexp) || \is_object($regexp) && \method_exists($regexp, '__toString') || (\is_bool($regexp) || \is_numeric($regexp)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($regexp) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($regexp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $regexp = (string) $regexp; + } + } + if (!\is_int($flags)) { + if (!(\is_bool($flags) || \is_numeric($flags))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($flags) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($flags) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $flags = (int) $flags; + } + } + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + $match = (\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags ? 'preg_match_all' : 'preg_match'; + if ($this->ignoreCase) { + $regexp .= 'i'; + } + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + if (\false === $match($regexp, $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { + $lastError = \preg_last_error(); + foreach (\get_defined_constants(\true)['pcre'] as $k => $v) { + if ($lastError === $v && '_ERROR' === \substr($k, -6)) { + throw new RuntimeException('Matching failed with ' . $k . '.'); + } + } + throw new RuntimeException('Matching failed with unknown error code.'); + } + } finally { + \restore_error_handler(); + } + $phabelReturn = $matches; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function padBoth($length, $padStr = ' ') + { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + if (!\is_string($padStr)) { + if (!(\is_string($padStr) || \is_object($padStr) && \method_exists($padStr, '__toString') || (\is_bool($padStr) || \is_numeric($padStr)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($padStr) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($padStr) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $padStr = (string) $padStr; + } + } + $str = clone $this; + $str->string = \str_pad($this->string, $length, $padStr, \STR_PAD_BOTH); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function padEnd($length, $padStr = ' ') + { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + if (!\is_string($padStr)) { + if (!(\is_string($padStr) || \is_object($padStr) && \method_exists($padStr, '__toString') || (\is_bool($padStr) || \is_numeric($padStr)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($padStr) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($padStr) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $padStr = (string) $padStr; + } + } + $str = clone $this; + $str->string = \str_pad($this->string, $length, $padStr, \STR_PAD_RIGHT); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function padStart($length, $padStr = ' ') + { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + if (!\is_string($padStr)) { + if (!(\is_string($padStr) || \is_object($padStr) && \method_exists($padStr, '__toString') || (\is_bool($padStr) || \is_numeric($padStr)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($padStr) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($padStr) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $padStr = (string) $padStr; + } + } + $str = clone $this; + $str->string = \str_pad($this->string, $length, $padStr, \STR_PAD_LEFT); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function prepend(...$prefix) + { + foreach ($prefix as $phabelVariadicIndex => $phabelVariadic) { + if (!\is_string($phabelVariadic)) { + if (!(\is_string($phabelVariadic) || \is_object($phabelVariadic) && \method_exists($phabelVariadic, '__toString') || (\is_bool($phabelVariadic) || \is_numeric($phabelVariadic)))) { + throw new \TypeError(__METHOD__ . '(): Argument #' . (1 + $phabelVariadicIndex) . ' must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($prefix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelVariadic = (string) $phabelVariadic; + } + } + } + $str = clone $this; + $str->string = (1 >= \count($prefix) ? isset($prefix[0]) ? $prefix[0] : '' : \implode('', $prefix)) . $str->string; + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function replace($from, $to) + { + if (!\is_string($from)) { + if (!(\is_string($from) || \is_object($from) && \method_exists($from, '__toString') || (\is_bool($from) || \is_numeric($from)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($from) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($from) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $from = (string) $from; + } + } + if (!\is_string($to)) { + if (!(\is_string($to) || \is_object($to) && \method_exists($to, '__toString') || (\is_bool($to) || \is_numeric($to)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($to) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($to) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $to = (string) $to; + } + } + $str = clone $this; + if ('' !== $from) { + $str->string = $this->ignoreCase ? \str_ireplace($from, $to, $this->string) : \str_replace($from, $to, $this->string); + } + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function replaceMatches($fromRegexp, $to) + { + if (!\is_string($fromRegexp)) { + if (!(\is_string($fromRegexp) || \is_object($fromRegexp) && \method_exists($fromRegexp, '__toString') || (\is_bool($fromRegexp) || \is_numeric($fromRegexp)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($fromRegexp) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($fromRegexp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $fromRegexp = (string) $fromRegexp; + } + } + if ($this->ignoreCase) { + $fromRegexp .= 'i'; + } + if (\is_array($to)) { + if (!\is_callable($to)) { + throw new \TypeError(\sprintf('Argument 2 passed to "%s::replaceMatches()" must be callable, array given.', static::class)); + } + $replace = 'preg_replace_callback'; + } else { + $replace = $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace'; + } + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + if (null === ($string = $replace($fromRegexp, $to, $this->string))) { + $lastError = \preg_last_error(); + foreach (\get_defined_constants(\true)['pcre'] as $k => $v) { + if ($lastError === $v && '_ERROR' === \substr($k, -6)) { + throw new RuntimeException('Matching failed with ' . $k . '.'); + } + } + throw new RuntimeException('Matching failed with unknown error code.'); + } + } finally { + \restore_error_handler(); + } + $str = clone $this; + $str->string = $string; + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function reverse() + { + $str = clone $this; + $str->string = \strrev($str->string); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function slice($start = 0, $length = null) + { + if (!\is_int($start)) { + if (!(\is_bool($start) || \is_numeric($start))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($start) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($start) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $start = (int) $start; + } + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + } + $str = clone $this; + $str->string = (string) \substr($this->string, $start, isset($length) ? $length : \PHP_INT_MAX); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function snake() + { + $str = $this->camel()->title(); + $str->string = \strtolower(\preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\\d])([A-Z])/'], 'Phabel\\1_\\2', $str->string)); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function splice($replacement, $start = 0, $length = null) + { + if (!\is_string($replacement)) { + if (!(\is_string($replacement) || \is_object($replacement) && \method_exists($replacement, '__toString') || (\is_bool($replacement) || \is_numeric($replacement)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($replacement) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($replacement) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $replacement = (string) $replacement; + } + } + if (!\is_int($start)) { + if (!(\is_bool($start) || \is_numeric($start))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($start) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($start) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $start = (int) $start; + } + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + } + $str = clone $this; + $str->string = \substr_replace($this->string, $replacement, $start, isset($length) ? $length : \PHP_INT_MAX); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function split($delimiter, $limit = null, $flags = null) + { + if (!\is_string($delimiter)) { + if (!(\is_string($delimiter) || \is_object($delimiter) && \method_exists($delimiter, '__toString') || (\is_bool($delimiter) || \is_numeric($delimiter)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($delimiter) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($delimiter) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $delimiter = (string) $delimiter; + } + } + if (!\is_null($limit)) { + if (!\is_int($limit)) { + if (!(\is_bool($limit) || \is_numeric($limit))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($limit) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($limit) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $limit = (int) $limit; + } + } + } + if (!\is_null($flags)) { + if (!\is_int($flags)) { + if (!(\is_bool($flags) || \is_numeric($flags))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($flags) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($flags) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $flags = (int) $flags; + } + } + } + if (1 > ($limit = isset($limit) ? $limit : \PHP_INT_MAX)) { + throw new InvalidArgumentException('Split limit must be a positive integer.'); + } + if ('' === $delimiter) { + throw new InvalidArgumentException('Split delimiter is empty.'); + } + if (null !== $flags) { + $phabelReturn = parent::split($delimiter, $limit, $flags); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $str = clone $this; + $chunks = $this->ignoreCase ? \preg_split('{' . \preg_quote($delimiter) . '}iD', $this->string, $limit) : \explode($delimiter, $this->string, $limit); + foreach ($chunks as &$chunk) { + $str->string = $chunk; + $chunk = clone $str; + } + $phabelReturn = $chunks; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function startsWith($prefix) + { + if ($prefix instanceof parent) { + $prefix = $prefix->string; + } elseif (!\is_string($prefix)) { + $phabelReturn = parent::startsWith($prefix); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = '' !== $prefix && 0 === ($this->ignoreCase ? \strncasecmp($this->string, $prefix, \strlen($prefix)) : \strncmp($this->string, $prefix, \strlen($prefix))); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function title($allWords = \false) + { + if (!\is_bool($allWords)) { + if (!(\is_bool($allWords) || \is_numeric($allWords) || \is_string($allWords))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($allWords) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($allWords) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $allWords = (bool) $allWords; + } + } + $str = clone $this; + $str->string = $allWords ? \ucwords($str->string) : \ucfirst($str->string); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function toUnicodeString($fromEncoding = null) + { + if (!\is_null($fromEncoding)) { + if (!\is_string($fromEncoding)) { + if (!(\is_string($fromEncoding) || \is_object($fromEncoding) && \method_exists($fromEncoding, '__toString') || (\is_bool($fromEncoding) || \is_numeric($fromEncoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($fromEncoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($fromEncoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $fromEncoding = (string) $fromEncoding; + } + } + } + $phabelReturn = new UnicodeString($this->toCodePointString($fromEncoding)->string); + if (!$phabelReturn instanceof UnicodeString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type UnicodeString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function toCodePointString($fromEncoding = null) + { + if (!\is_null($fromEncoding)) { + if (!\is_string($fromEncoding)) { + if (!(\is_string($fromEncoding) || \is_object($fromEncoding) && \method_exists($fromEncoding, '__toString') || (\is_bool($fromEncoding) || \is_numeric($fromEncoding)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($fromEncoding) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($fromEncoding) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $fromEncoding = (string) $fromEncoding; + } + } + } + $u = new CodePointString(); + if (\in_array($fromEncoding, [null, 'utf8', 'utf-8', 'UTF8', 'UTF-8'], \true) && \preg_match('//u', $this->string)) { + $u->string = $this->string; + $phabelReturn = $u; + if (!$phabelReturn instanceof CodePointString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type CodePointString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + try { + $validEncoding = \false !== \mb_detect_encoding($this->string, isset($fromEncoding) ? $fromEncoding : 'Windows-1252', \true); + } catch (InvalidArgumentException $e) { + if (!\function_exists('iconv')) { + throw $e; + } + $u->string = \iconv(isset($fromEncoding) ? $fromEncoding : 'Windows-1252', 'UTF-8', $this->string); + $phabelReturn = $u; + if (!$phabelReturn instanceof CodePointString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type CodePointString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + } finally { + \restore_error_handler(); + } + if (!$validEncoding) { + throw new InvalidArgumentException(\sprintf('Invalid "%s" string.', isset($fromEncoding) ? $fromEncoding : 'Windows-1252')); + } + $u->string = \mb_convert_encoding($this->string, 'UTF-8', isset($fromEncoding) ? $fromEncoding : 'Windows-1252'); + $phabelReturn = $u; + if (!$phabelReturn instanceof CodePointString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type CodePointString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function trim($chars = " \t\n\r\x00\v\f") + { + if (!\is_string($chars)) { + if (!(\is_string($chars) || \is_object($chars) && \method_exists($chars, '__toString') || (\is_bool($chars) || \is_numeric($chars)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($chars) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($chars) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $chars = (string) $chars; + } + } + $str = clone $this; + $str->string = \trim($str->string, $chars); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function trimEnd($chars = " \t\n\r\x00\v\f") + { + if (!\is_string($chars)) { + if (!(\is_string($chars) || \is_object($chars) && \method_exists($chars, '__toString') || (\is_bool($chars) || \is_numeric($chars)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($chars) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($chars) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $chars = (string) $chars; + } + } + $str = clone $this; + $str->string = \rtrim($str->string, $chars); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function trimStart($chars = " \t\n\r\x00\v\f") + { + if (!\is_string($chars)) { + if (!(\is_string($chars) || \is_object($chars) && \method_exists($chars, '__toString') || (\is_bool($chars) || \is_numeric($chars)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($chars) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($chars) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $chars = (string) $chars; + } + } + $str = clone $this; + $str->string = \ltrim($str->string, $chars); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function upper() + { + $str = clone $this; + $str->string = \strtoupper($str->string); + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function width($ignoreAnsiDecoration = \true) + { + if (!\is_bool($ignoreAnsiDecoration)) { + if (!(\is_bool($ignoreAnsiDecoration) || \is_numeric($ignoreAnsiDecoration) || \is_string($ignoreAnsiDecoration))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($ignoreAnsiDecoration) must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($ignoreAnsiDecoration) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $ignoreAnsiDecoration = (bool) $ignoreAnsiDecoration; + } + } + $string = \preg_match('//u', $this->string) ? $this->string : \preg_replace('/[\\x80-\\xFF]/', '?', $this->string); + $phabelReturn = (new CodePointString($string))->width($ignoreAnsiDecoration); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/string/CodePointString.php b/vendor-bundle/symfony/string/CodePointString.php new file mode 100644 index 000000000..2ed05a70f --- /dev/null +++ b/vendor-bundle/symfony/string/CodePointString.php @@ -0,0 +1,545 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String; + +use Phabel\Symfony\Component\String\Exception\ExceptionInterface; +use Phabel\Symfony\Component\String\Exception\InvalidArgumentException; +/** + * Represents a string of Unicode code points encoded as UTF-8. + * + * @author Nicolas Grekas + * @author Hugo Hamon + * + * @throws ExceptionInterface + */ +class CodePointString extends AbstractUnicodeString +{ + public function __construct($string = '') + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + if ('' !== $string && !\preg_match('//u', $string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $this->string = $string; + } + public function append(...$suffix) + { + foreach ($suffix as $phabelVariadicIndex => $phabelVariadic) { + if (!\is_string($phabelVariadic)) { + if (!(\is_string($phabelVariadic) || \is_object($phabelVariadic) && \method_exists($phabelVariadic, '__toString') || (\is_bool($phabelVariadic) || \is_numeric($phabelVariadic)))) { + throw new \TypeError(__METHOD__ . '(): Argument #' . (1 + $phabelVariadicIndex) . ' must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($suffix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelVariadic = (string) $phabelVariadic; + } + } + } + $str = clone $this; + $str->string .= 1 >= \count($suffix) ? isset($suffix[0]) ? $suffix[0] : '' : \implode('', $suffix); + if (!\preg_match('//u', $str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function chunk($length = 1) + { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + if (1 > $length) { + throw new InvalidArgumentException('The chunk length must be greater than zero.'); + } + if ('' === $this->string) { + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $rx = '/('; + while (65535 < $length) { + $rx .= '.{65535}'; + $length -= 65535; + } + $rx .= '.{' . $length . '})/us'; + $str = clone $this; + $chunks = []; + foreach (\preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) { + $str->string = $chunk; + $chunks[] = clone $str; + } + $phabelReturn = $chunks; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function codePointsAt($offset) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + $str = $offset ? $this->slice($offset, 1) : $this; + $phabelReturn = '' === $str->string ? [] : [\mb_ord($str->string, 'UTF-8')]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function endsWith($suffix) + { + if ($suffix instanceof AbstractString) { + $suffix = $suffix->string; + } elseif (\is_array($suffix) || $suffix instanceof \Traversable) { + $phabelReturn = parent::endsWith($suffix); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } else { + $suffix = (string) $suffix; + } + if ('' === $suffix || !\preg_match('//u', $suffix)) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if ($this->ignoreCase) { + $phabelReturn = \preg_match('{' . \preg_quote($suffix) . '$}iuD', $this->string); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = \strlen($this->string) >= \strlen($suffix) && 0 === \substr_compare($this->string, $suffix, -\strlen($suffix)); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function equalsTo($string) + { + if ($string instanceof AbstractString) { + $string = $string->string; + } elseif (\is_array($string) || $string instanceof \Traversable) { + $phabelReturn = parent::equalsTo($string); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } else { + $string = (string) $string; + } + if ('' !== $string && $this->ignoreCase) { + $phabelReturn = \strlen($string) === \strlen($this->string) && 0 === \mb_stripos($this->string, $string, 0, 'UTF-8'); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = $string === $this->string; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function indexOf($needle, $offset = 0) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (\is_array($needle) || $needle instanceof \Traversable) { + $phabelReturn = parent::indexOf($needle, $offset); + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } else { + $needle = (string) $needle; + } + if ('' === $needle) { + $phabelReturn = null; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + $i = $this->ignoreCase ? \mb_stripos($this->string, $needle, $offset, 'UTF-8') : \mb_strpos($this->string, $needle, $offset, 'UTF-8'); + $phabelReturn = \false === $i ? null : $i; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + public function indexOfLast($needle, $offset = 0) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (\is_array($needle) || $needle instanceof \Traversable) { + $phabelReturn = parent::indexOfLast($needle, $offset); + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } else { + $needle = (string) $needle; + } + if ('' === $needle) { + $phabelReturn = null; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + $i = $this->ignoreCase ? \mb_strripos($this->string, $needle, $offset, 'UTF-8') : \mb_strrpos($this->string, $needle, $offset, 'UTF-8'); + $phabelReturn = \false === $i ? null : $i; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + public function length() + { + $phabelReturn = \mb_strlen($this->string, 'UTF-8'); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + public function prepend(...$prefix) + { + foreach ($prefix as $phabelVariadicIndex => $phabelVariadic) { + if (!\is_string($phabelVariadic)) { + if (!(\is_string($phabelVariadic) || \is_object($phabelVariadic) && \method_exists($phabelVariadic, '__toString') || (\is_bool($phabelVariadic) || \is_numeric($phabelVariadic)))) { + throw new \TypeError(__METHOD__ . '(): Argument #' . (1 + $phabelVariadicIndex) . ' must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($prefix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelVariadic = (string) $phabelVariadic; + } + } + } + $str = clone $this; + $str->string = (1 >= \count($prefix) ? isset($prefix[0]) ? $prefix[0] : '' : \implode('', $prefix)) . $this->string; + if (!\preg_match('//u', $str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function replace($from, $to) + { + if (!\is_string($from)) { + if (!(\is_string($from) || \is_object($from) && \method_exists($from, '__toString') || (\is_bool($from) || \is_numeric($from)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($from) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($from) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $from = (string) $from; + } + } + if (!\is_string($to)) { + if (!(\is_string($to) || \is_object($to) && \method_exists($to, '__toString') || (\is_bool($to) || \is_numeric($to)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($to) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($to) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $to = (string) $to; + } + } + $str = clone $this; + if ('' === $from || !\preg_match('//u', $from)) { + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if ('' !== $to && !\preg_match('//u', $to)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + if ($this->ignoreCase) { + $str->string = \implode($to, \preg_split('{' . \preg_quote($from) . '}iuD', $this->string)); + } else { + $str->string = \str_replace($from, $to, $this->string); + } + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function slice($start = 0, $length = null) + { + if (!\is_int($start)) { + if (!(\is_bool($start) || \is_numeric($start))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($start) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($start) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $start = (int) $start; + } + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + } + $str = clone $this; + $str->string = \mb_substr($this->string, $start, $length, 'UTF-8'); + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function splice($replacement, $start = 0, $length = null) + { + if (!\is_string($replacement)) { + if (!(\is_string($replacement) || \is_object($replacement) && \method_exists($replacement, '__toString') || (\is_bool($replacement) || \is_numeric($replacement)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($replacement) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($replacement) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $replacement = (string) $replacement; + } + } + if (!\is_int($start)) { + if (!(\is_bool($start) || \is_numeric($start))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($start) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($start) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $start = (int) $start; + } + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + } + if (!\preg_match('//u', $replacement)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $str = clone $this; + $start = $start ? \strlen(\mb_substr($this->string, 0, $start, 'UTF-8')) : 0; + $length = $length ? \strlen(\mb_substr($this->string, $start, $length, 'UTF-8')) : $length; + $str->string = \substr_replace($this->string, $replacement, $start, isset($length) ? $length : \PHP_INT_MAX); + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function split($delimiter, $limit = null, $flags = null) + { + if (!\is_string($delimiter)) { + if (!(\is_string($delimiter) || \is_object($delimiter) && \method_exists($delimiter, '__toString') || (\is_bool($delimiter) || \is_numeric($delimiter)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($delimiter) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($delimiter) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $delimiter = (string) $delimiter; + } + } + if (!\is_null($limit)) { + if (!\is_int($limit)) { + if (!(\is_bool($limit) || \is_numeric($limit))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($limit) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($limit) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $limit = (int) $limit; + } + } + } + if (!\is_null($flags)) { + if (!\is_int($flags)) { + if (!(\is_bool($flags) || \is_numeric($flags))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($flags) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($flags) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $flags = (int) $flags; + } + } + } + if (1 > ($limit = isset($limit) ? $limit : \PHP_INT_MAX)) { + throw new InvalidArgumentException('Split limit must be a positive integer.'); + } + if ('' === $delimiter) { + throw new InvalidArgumentException('Split delimiter is empty.'); + } + if (null !== $flags) { + $phabelReturn = parent::split($delimiter . 'u', $limit, $flags); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + if (!\preg_match('//u', $delimiter)) { + throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.'); + } + $str = clone $this; + $chunks = $this->ignoreCase ? \preg_split('{' . \preg_quote($delimiter) . '}iuD', $this->string, $limit) : \explode($delimiter, $this->string, $limit); + foreach ($chunks as &$chunk) { + $str->string = $chunk; + $chunk = clone $str; + } + $phabelReturn = $chunks; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function startsWith($prefix) + { + if ($prefix instanceof AbstractString) { + $prefix = $prefix->string; + } elseif (\is_array($prefix) || $prefix instanceof \Traversable) { + $phabelReturn = parent::startsWith($prefix); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } else { + $prefix = (string) $prefix; + } + if ('' === $prefix || !\preg_match('//u', $prefix)) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if ($this->ignoreCase) { + $phabelReturn = 0 === \mb_stripos($this->string, $prefix, 0, 'UTF-8'); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = 0 === \strncmp($this->string, $prefix, \strlen($prefix)); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/string/Exception/ExceptionInterface.php b/vendor-bundle/symfony/string/Exception/ExceptionInterface.php new file mode 100644 index 000000000..1cdd82670 --- /dev/null +++ b/vendor-bundle/symfony/string/Exception/ExceptionInterface.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String\Exception; + +interface ExceptionInterface extends \Throwable +{ +} diff --git a/vendor-bundle/symfony/string/Exception/InvalidArgumentException.php b/vendor-bundle/symfony/string/Exception/InvalidArgumentException.php new file mode 100644 index 000000000..3722bc76b --- /dev/null +++ b/vendor-bundle/symfony/string/Exception/InvalidArgumentException.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String\Exception; + +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor-bundle/symfony/string/Exception/RuntimeException.php b/vendor-bundle/symfony/string/Exception/RuntimeException.php new file mode 100644 index 000000000..b44bf0347 --- /dev/null +++ b/vendor-bundle/symfony/string/Exception/RuntimeException.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String\Exception; + +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor-bundle/symfony/string/Inflector/EnglishInflector.php b/vendor-bundle/symfony/string/Inflector/EnglishInflector.php new file mode 100644 index 000000000..b2920ae5d --- /dev/null +++ b/vendor-bundle/symfony/string/Inflector/EnglishInflector.php @@ -0,0 +1,422 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String\Inflector; + +final class EnglishInflector implements InflectorInterface +{ + /** + * Map English plural to singular suffixes. + * + * @see http://english-zone.com/spelling/plurals.html + */ + const PLURAL_MAP = [ + // First entry: plural suffix, reversed + // Second entry: length of plural suffix + // Third entry: Whether the suffix may succeed a vocal + // Fourth entry: Whether the suffix may succeed a consonant + // Fifth entry: singular suffix, normal + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + ['a', 1, \true, \true, ['on', 'um']], + // nebulae (nebula) + ['ea', 2, \true, \true, 'a'], + // services (service) + ['secivres', 8, \true, \true, 'service'], + // mice (mouse), lice (louse) + ['eci', 3, \false, \true, 'ouse'], + // geese (goose) + ['esee', 4, \false, \true, 'oose'], + // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) + ['i', 1, \true, \true, 'us'], + // men (man), women (woman) + ['nem', 3, \true, \true, 'man'], + // children (child) + ['nerdlihc', 8, \true, \true, 'child'], + // oxen (ox) + ['nexo', 4, \false, \false, 'ox'], + // indices (index), appendices (appendix), prices (price) + ['seci', 4, \false, \true, ['ex', 'ix', 'ice']], + // selfies (selfie) + ['seifles', 7, \true, \true, 'selfie'], + // movies (movie) + ['seivom', 6, \true, \true, 'movie'], + // conspectuses (conspectus), prospectuses (prospectus) + ['sesutcep', 8, \true, \true, 'pectus'], + // feet (foot) + ['teef', 4, \true, \true, 'foot'], + // geese (goose) + ['eseeg', 5, \true, \true, 'goose'], + // teeth (tooth) + ['hteet', 5, \true, \true, 'tooth'], + // news (news) + ['swen', 4, \true, \true, 'news'], + // series (series) + ['seires', 6, \true, \true, 'series'], + // babies (baby) + ['sei', 3, \false, \true, 'y'], + // accesses (access), addresses (address), kisses (kiss) + ['sess', 4, \true, \false, 'ss'], + // analyses (analysis), ellipses (ellipsis), fungi (fungus), + // neuroses (neurosis), theses (thesis), emphases (emphasis), + // oases (oasis), crises (crisis), houses (house), bases (base), + // atlases (atlas) + ['ses', 3, \true, \true, ['s', 'se', 'sis']], + // objectives (objective), alternative (alternatives) + ['sevit', 5, \true, \true, 'tive'], + // drives (drive) + ['sevird', 6, \false, \true, 'drive'], + // lives (life), wives (wife) + ['sevi', 4, \false, \true, 'ife'], + // moves (move) + ['sevom', 5, \true, \true, 'move'], + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf), caves (cave), staves (staff) + ['sev', 3, \true, \true, ['f', 've', 'ff']], + // axes (axis), axes (ax), axes (axe) + ['sexa', 4, \false, \false, ['ax', 'axe', 'axis']], + // indexes (index), matrixes (matrix) + ['sex', 3, \true, \false, 'x'], + // quizzes (quiz) + ['sezz', 4, \true, \false, 'z'], + // bureaus (bureau) + ['suae', 4, \false, \true, 'eau'], + // fees (fee), trees (tree), employees (employee) + ['see', 3, \true, \true, 'ee'], + // edges (edge) + ['segd', 4, \true, \true, 'dge'], + // roses (rose), garages (garage), cassettes (cassette), + // waltzes (waltz), heroes (hero), bushes (bush), arches (arch), + // shoes (shoe) + ['se', 2, \true, \true, ['', 'e']], + // tags (tag) + ['s', 1, \true, \true, ''], + // chateaux (chateau) + ['xuae', 4, \false, \true, 'eau'], + // people (person) + ['elpoep', 6, \true, \true, 'person'], + ]; + /** + * Map English singular to plural suffixes. + * + * @see http://english-zone.com/spelling/plurals.html + */ + const SINGULAR_MAP = [ + // First entry: singular suffix, reversed + // Second entry: length of singular suffix + // Third entry: Whether the suffix may succeed a vocal + // Fourth entry: Whether the suffix may succeed a consonant + // Fifth entry: plural suffix, normal + // criterion (criteria) + ['airetirc', 8, \false, \false, 'criterion'], + // nebulae (nebula) + ['aluben', 6, \false, \false, 'nebulae'], + // children (child) + ['dlihc', 5, \true, \true, 'children'], + // prices (price) + ['eci', 3, \false, \true, 'ices'], + // services (service) + ['ecivres', 7, \true, \true, 'services'], + // lives (life), wives (wife) + ['efi', 3, \false, \true, 'ives'], + // selfies (selfie) + ['eifles', 6, \true, \true, 'selfies'], + // movies (movie) + ['eivom', 5, \true, \true, 'movies'], + // lice (louse) + ['esuol', 5, \false, \true, 'lice'], + // mice (mouse) + ['esuom', 5, \false, \true, 'mice'], + // geese (goose) + ['esoo', 4, \false, \true, 'eese'], + // houses (house), bases (base) + ['es', 2, \true, \true, 'ses'], + // geese (goose) + ['esoog', 5, \true, \true, 'geese'], + // caves (cave) + ['ev', 2, \true, \true, 'ves'], + // drives (drive) + ['evird', 5, \false, \true, 'drives'], + // objectives (objective), alternative (alternatives) + ['evit', 4, \true, \true, 'tives'], + // moves (move) + ['evom', 4, \true, \true, 'moves'], + // staves (staff) + ['ffats', 5, \true, \true, 'staves'], + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) + ['ff', 2, \true, \true, 'ffs'], + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) + ['f', 1, \true, \true, ['fs', 'ves']], + // arches (arch) + ['hc', 2, \true, \true, 'ches'], + // bushes (bush) + ['hs', 2, \true, \true, 'shes'], + // teeth (tooth) + ['htoot', 5, \true, \true, 'teeth'], + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + ['mu', 2, \true, \true, 'a'], + // men (man), women (woman) + ['nam', 3, \true, \true, 'men'], + // people (person) + ['nosrep', 6, \true, \true, ['persons', 'people']], + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + ['noi', 3, \true, \true, 'ions'], + // coupon (coupons) + ['nop', 3, \true, \true, 'pons'], + // seasons (season), treasons (treason), poisons (poison), lessons (lesson) + ['nos', 3, \true, \true, 'sons'], + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + ['no', 2, \true, \true, 'a'], + // echoes (echo) + ['ohce', 4, \true, \true, 'echoes'], + // heroes (hero) + ['oreh', 4, \true, \true, 'heroes'], + // atlases (atlas) + ['salta', 5, \true, \true, 'atlases'], + // irises (iris) + ['siri', 4, \true, \true, 'irises'], + // analyses (analysis), ellipses (ellipsis), neuroses (neurosis) + // theses (thesis), emphases (emphasis), oases (oasis), + // crises (crisis) + ['sis', 3, \true, \true, 'ses'], + // accesses (access), addresses (address), kisses (kiss) + ['ss', 2, \true, \false, 'sses'], + // syllabi (syllabus) + ['suballys', 8, \true, \true, 'syllabi'], + // buses (bus) + ['sub', 3, \true, \true, 'buses'], + // circuses (circus) + ['suc', 3, \true, \true, 'cuses'], + // conspectuses (conspectus), prospectuses (prospectus) + ['sutcep', 6, \true, \true, 'pectuses'], + // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) + ['su', 2, \true, \true, 'i'], + // news (news) + ['swen', 4, \true, \true, 'news'], + // feet (foot) + ['toof', 4, \true, \true, 'feet'], + // chateaux (chateau), bureaus (bureau) + ['uae', 3, \false, \true, ['eaus', 'eaux']], + // oxen (ox) + ['xo', 2, \false, \false, 'oxen'], + // hoaxes (hoax) + ['xaoh', 4, \true, \false, 'hoaxes'], + // indices (index) + ['xedni', 5, \false, \true, ['indicies', 'indexes']], + // boxes (box) + ['xo', 2, \false, \true, 'oxes'], + // indexes (index), matrixes (matrix) + ['x', 1, \true, \false, ['cies', 'xes']], + // appendices (appendix) + ['xi', 2, \false, \true, 'ices'], + // babies (baby) + ['y', 1, \false, \true, 'ies'], + // quizzes (quiz) + ['ziuq', 4, \true, \false, 'quizzes'], + // waltzes (waltz) + ['z', 1, \true, \true, 'zes'], + ]; + /** + * A list of words which should not be inflected, reversed. + */ + const UNINFLECTED = [ + '', + // data + 'atad', + // deer + 'reed', + // feedback + 'kcabdeef', + // fish + 'hsif', + // info + 'ofni', + // moose + 'esoom', + // series + 'seires', + // sheep + 'peehs', + // species + 'seiceps', + ]; + /** + * {@inheritdoc} + */ + public function singularize($plural) + { + if (!\is_string($plural)) { + if (!(\is_string($plural) || \is_object($plural) && \method_exists($plural, '__toString') || (\is_bool($plural) || \is_numeric($plural)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plural) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plural) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $plural = (string) $plural; + } + } + $pluralRev = \strrev($plural); + $lowerPluralRev = \strtolower($pluralRev); + $pluralLength = \strlen($lowerPluralRev); + // Check if the word is one which is not inflected, return early if so + if (\in_array($lowerPluralRev, self::UNINFLECTED, \true)) { + $phabelReturn = [$plural]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + // The outer loop iterates over the entries of the plural table + // The inner loop $j iterates over the characters of the plural suffix + // in the plural table to compare them with the characters of the actual + // given plural suffix + foreach (self::PLURAL_MAP as $map) { + $suffix = $map[0]; + $suffixLength = $map[1]; + $j = 0; + // Compare characters in the plural table and of the suffix of the + // given plural one by one + while ($suffix[$j] === $lowerPluralRev[$j]) { + // Let $j point to the next character + ++$j; + // Successfully compared the last character + // Add an entry with the singular suffix to the singular array + if ($j === $suffixLength) { + // Is there any character preceding the suffix in the plural string? + if ($j < $pluralLength) { + $nextIsVocal = \false !== \strpos('aeiou', $lowerPluralRev[$j]); + if (!$map[2] && $nextIsVocal) { + // suffix may not succeed a vocal but next char is one + break; + } + if (!$map[3] && !$nextIsVocal) { + // suffix may not succeed a consonant but next char is one + break; + } + } + $newBase = \substr($plural, 0, $pluralLength - $suffixLength); + $newSuffix = $map[4]; + // Check whether the first character in the plural suffix + // is uppercased. If yes, uppercase the first character in + // the singular suffix too + $firstUpper = \ctype_upper($pluralRev[$j - 1]); + if (\is_array($newSuffix)) { + $singulars = []; + foreach ($newSuffix as $newSuffixEntry) { + $singulars[] = $newBase . ($firstUpper ? \ucfirst($newSuffixEntry) : $newSuffixEntry); + } + $phabelReturn = $singulars; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = [$newBase . ($firstUpper ? \ucfirst($newSuffix) : $newSuffix)]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + // Suffix is longer than word + if ($j === $pluralLength) { + break; + } + } + } + $phabelReturn = [$plural]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // Assume that plural and singular is identical + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function pluralize($singular) + { + if (!\is_string($singular)) { + if (!(\is_string($singular) || \is_object($singular) && \method_exists($singular, '__toString') || (\is_bool($singular) || \is_numeric($singular)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($singular) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($singular) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $singular = (string) $singular; + } + } + $singularRev = \strrev($singular); + $lowerSingularRev = \strtolower($singularRev); + $singularLength = \strlen($lowerSingularRev); + // Check if the word is one which is not inflected, return early if so + if (\in_array($lowerSingularRev, self::UNINFLECTED, \true)) { + $phabelReturn = [$singular]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + // The outer loop iterates over the entries of the singular table + // The inner loop $j iterates over the characters of the singular suffix + // in the singular table to compare them with the characters of the actual + // given singular suffix + foreach (self::SINGULAR_MAP as $map) { + $suffix = $map[0]; + $suffixLength = $map[1]; + $j = 0; + // Compare characters in the singular table and of the suffix of the + // given plural one by one + while ($suffix[$j] === $lowerSingularRev[$j]) { + // Let $j point to the next character + ++$j; + // Successfully compared the last character + // Add an entry with the plural suffix to the plural array + if ($j === $suffixLength) { + // Is there any character preceding the suffix in the plural string? + if ($j < $singularLength) { + $nextIsVocal = \false !== \strpos('aeiou', $lowerSingularRev[$j]); + if (!$map[2] && $nextIsVocal) { + // suffix may not succeed a vocal but next char is one + break; + } + if (!$map[3] && !$nextIsVocal) { + // suffix may not succeed a consonant but next char is one + break; + } + } + $newBase = \substr($singular, 0, $singularLength - $suffixLength); + $newSuffix = $map[4]; + // Check whether the first character in the singular suffix + // is uppercased. If yes, uppercase the first character in + // the singular suffix too + $firstUpper = \ctype_upper($singularRev[$j - 1]); + if (\is_array($newSuffix)) { + $plurals = []; + foreach ($newSuffix as $newSuffixEntry) { + $plurals[] = $newBase . ($firstUpper ? \ucfirst($newSuffixEntry) : $newSuffixEntry); + } + $phabelReturn = $plurals; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $phabelReturn = [$newBase . ($firstUpper ? \ucfirst($newSuffix) : $newSuffix)]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + // Suffix is longer than word + if ($j === $singularLength) { + break; + } + } + } + $phabelReturn = [$singular . 's']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + // Assume that plural is singular with a trailing `s` + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/string/Inflector/FrenchInflector.php b/vendor-bundle/symfony/string/Inflector/FrenchInflector.php new file mode 100644 index 000000000..d4c7312b9 --- /dev/null +++ b/vendor-bundle/symfony/string/Inflector/FrenchInflector.php @@ -0,0 +1,181 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String\Inflector; + +/** + * French inflector. + * + * This class does only inflect nouns; not adjectives nor composed words like "soixante-dix". + */ +final class FrenchInflector implements InflectorInterface +{ + /** + * A list of all rules for pluralise. + * + * @see https://la-conjugaison.nouvelobs.com/regles/grammaire/le-pluriel-des-noms-121.php + */ + const PLURALIZE_REGEXP = [ + // First entry: regexp + // Second entry: replacement + // Words finishing with "s", "x" or "z" are invariables + // Les mots finissant par "s", "x" ou "z" sont invariables + ['/(s|x|z)$/i', '\\1'], + // Words finishing with "eau" are pluralized with a "x" + // Les mots finissant par "eau" prennent tous un "x" au pluriel + ['/(eau)$/i', '\\1x'], + // Words finishing with "au" are pluralized with a "x" excepted "landau" + // Les mots finissant par "au" prennent un "x" au pluriel sauf "landau" + ['/^(landau)$/i', '\\1s'], + ['/(au)$/i', '\\1x'], + // Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu" + // Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu" + ['/^(pneu|bleu|émeu)$/i', '\\1s'], + ['/(eu)$/i', '\\1x'], + // Words finishing with "al" are pluralized with a "aux" excepted + // Les mots finissant en "al" se terminent en "aux" sauf + ['/^(bal|carnaval|caracal|chacal|choral|corral|étal|festival|récital|val)$/i', '\\1s'], + ['/al$/i', '\\1aux'], + // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux + ['/^(aspir|b|cor|ém|ferm|soupir|trav|vant|vitr)ail$/i', '\\1aux'], + // Bijou, caillou, chou, genou, hibou, joujou et pou qui prennent un x au pluriel + ['/^(bij|caill|ch|gen|hib|jouj|p)ou$/i', '\\1oux'], + // Invariable words + ['/^(cinquante|soixante|mille)$/i', '\\1'], + // French titles + ['/^(mon|ma)(sieur|dame|demoiselle|seigneur)$/', 'Phabel\\mes\\2s'], + ['/^(Mon|Ma)(sieur|dame|demoiselle|seigneur)$/', 'Phabel\\Mes\\2s'], + ]; + /** + * A list of all rules for singularize. + */ + const SINGULARIZE_REGEXP = [ + // First entry: regexp + // Second entry: replacement + // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux + ['/((aspir|b|cor|ém|ferm|soupir|trav|vant|vitr))aux$/i', '\\1ail'], + // Words finishing with "eau" are pluralized with a "x" + // Les mots finissant par "eau" prennent tous un "x" au pluriel + ['/(eau)x$/i', '\\1'], + // Words finishing with "al" are pluralized with a "aux" expected + // Les mots finissant en "al" se terminent en "aux" sauf + ['/(amir|anim|arsen|boc|can|capit|capor|chev|crist|génér|hopit|hôpit|idé|journ|littor|loc|m|mét|minér|princip|radic|termin)aux$/i', '\\1al'], + // Words finishing with "au" are pluralized with a "x" excepted "landau" + // Les mots finissant par "au" prennent un "x" au pluriel sauf "landau" + ['/(au)x$/i', '\\1'], + // Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu" + // Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu" + ['/(eu)x$/i', '\\1'], + // Words finishing with "ou" are pluralized with a "s" excepted bijou, caillou, chou, genou, hibou, joujou, pou + // Les mots finissant par "ou" prennent un "s" sauf bijou, caillou, chou, genou, hibou, joujou, pou + ['/(bij|caill|ch|gen|hib|jouj|p)oux$/i', '\\1ou'], + // French titles + ['/^mes(dame|demoiselle)s$/', 'Phabel\\ma\\1'], + ['/^Mes(dame|demoiselle)s$/', 'Phabel\\Ma\\1'], + ['/^mes(sieur|seigneur)s$/', 'Phabel\\mon\\1'], + ['/^Mes(sieur|seigneur)s$/', 'Phabel\\Mon\\1'], + //Default rule + ['/s$/i', ''], + ]; + /** + * A list of words which should not be inflected. + * This list is only used by singularize. + */ + const UNINFLECTED = '/^(abcès|accès|abus|albatros|anchois|anglais|autobus|bois|brebis|carquois|cas|chas|colis|concours|corps|cours|cyprès|décès|devis|discours|dos|embarras|engrais|entrelacs|excès|fils|fois|gâchis|gars|glas|héros|intrus|jars|jus|kermès|lacis|legs|lilas|marais|mars|matelas|mépris|mets|mois|mors|obus|os|palais|paradis|parcours|pardessus|pays|plusieurs|poids|pois|pouls|printemps|processus|progrès|puits|pus|rabais|radis|recors|recours|refus|relais|remords|remous|rictus|rhinocéros|repas|rubis|sas|secours|sens|souris|succès|talus|tapis|tas|taudis|temps|tiers|univers|velours|verglas|vernis|virus)$/i'; + /** + * {@inheritdoc} + */ + public function singularize($plural) + { + if (!\is_string($plural)) { + if (!(\is_string($plural) || \is_object($plural) && \method_exists($plural, '__toString') || (\is_bool($plural) || \is_numeric($plural)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($plural) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($plural) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $plural = (string) $plural; + } + } + if ($this->isInflectedWord($plural)) { + $phabelReturn = [$plural]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + foreach (self::SINGULARIZE_REGEXP as $rule) { + list($regexp, $replace) = $rule; + if (1 === \preg_match($regexp, $plural)) { + $phabelReturn = [\preg_replace($regexp, $replace, $plural)]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + } + $phabelReturn = [$plural]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * {@inheritdoc} + */ + public function pluralize($singular) + { + if (!\is_string($singular)) { + if (!(\is_string($singular) || \is_object($singular) && \method_exists($singular, '__toString') || (\is_bool($singular) || \is_numeric($singular)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($singular) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($singular) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $singular = (string) $singular; + } + } + if ($this->isInflectedWord($singular)) { + $phabelReturn = [$singular]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + foreach (self::PLURALIZE_REGEXP as $rule) { + list($regexp, $replace) = $rule; + if (1 === \preg_match($regexp, $singular)) { + $phabelReturn = [\preg_replace($regexp, $replace, $singular)]; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + } + $phabelReturn = [$singular . 's']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function isInflectedWord($word) + { + if (!\is_string($word)) { + if (!(\is_string($word) || \is_object($word) && \method_exists($word, '__toString') || (\is_bool($word) || \is_numeric($word)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($word) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($word) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $word = (string) $word; + } + } + $phabelReturn = 1 === \preg_match(self::UNINFLECTED, $word); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/string/Inflector/InflectorInterface.php b/vendor-bundle/symfony/string/Inflector/InflectorInterface.php new file mode 100644 index 000000000..973628316 --- /dev/null +++ b/vendor-bundle/symfony/string/Inflector/InflectorInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String\Inflector; + +interface InflectorInterface +{ + /** + * Returns the singular forms of a string. + * + * If the method can't determine the form with certainty, several possible singulars are returned. + * + * @return string[] An array of possible singular forms + */ + public function singularize($plural); + /** + * Returns the plural forms of a string. + * + * If the method can't determine the form with certainty, several possible plurals are returned. + * + * @return string[] An array of possible plural forms + */ + public function pluralize($singular); +} diff --git a/vendor-bundle/symfony/string/LazyString.php b/vendor-bundle/symfony/string/LazyString.php new file mode 100644 index 000000000..64144d4ee --- /dev/null +++ b/vendor-bundle/symfony/string/LazyString.php @@ -0,0 +1,225 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String; + +/** + * A string whose value is computed lazily by a callback. + * + * @author Nicolas Grekas + */ +class LazyString implements \Stringable, \JsonSerializable +{ + private $value; + /** + * @param callable|array $callback A callable or a [Closure, method] lazy-callable + * + * @return static + */ + public static function fromCallable($callback, ...$arguments) + { + if (!\is_callable($callback) && !(\is_array($callback) && isset($callback[0]) && $callback[0] instanceof \Closure && 2 >= \count($callback))) { + throw new \TypeError(\sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, \get_debug_type($callback))); + } + $lazyString = new static(); + $lazyString->value = static function () use(&$callback, &$arguments, &$value) { + if (null !== $arguments) { + if (!\is_callable($callback)) { + $callback[0] = $callback[0](); + $callback[1] = isset($callback[1]) ? $callback[1] : '__invoke'; + } + $value = $callback(...$arguments); + $callback = self::getPrettyName($callback); + $arguments = null; + } + $phabelReturn = isset($value) ? $value : ''; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + }; + $phabelReturn = $lazyString; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * @param string|int|float|bool|\Stringable $value + * + * @return static + */ + public static function fromStringable($value) + { + if (!self::isStringable($value)) { + throw new \TypeError(\sprintf('Argument 1 passed to "%s()" must be a scalar or a stringable object, "%s" given.', __METHOD__, \get_debug_type($value))); + } + if (\is_object($value)) { + $phabelReturn = static::fromCallable([$value, '__toString']); + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $lazyString = new static(); + $lazyString->value = (string) $value; + $phabelReturn = $lazyString; + if (!$phabelReturn instanceof self) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . self::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + /** + * Tells whether the provided value can be cast to string. + */ + public static final function isStringable($value) + { + $phabelReturn = \is_string($value) || $value instanceof self || (\is_object($value) ? \method_exists($value, '__toString') : \is_scalar($value)); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * Casts scalars and stringable objects to strings. + * + * @param object|string|int|float|bool $value + * + * @throws \TypeError When the provided value is not stringable + */ + public static final function resolve($value) + { + $phabelReturn = $value; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return string + */ + public function __toString() + { + if (\is_string($this->value)) { + return $this->value; + } + try { + $phabel_102c5e0d12ae1b38 = $this->value; + return $this->value = $phabel_102c5e0d12ae1b38(); + } catch (\Exception $e) { + if (\TypeError::class === \get_class($e) && __FILE__ === $e->getFile()) { + $type = \explode(', ', $e->getMessage()); + $type = \substr(\array_pop($type), 0, -\strlen(' returned')); + $r = new \ReflectionFunction($this->value); + $callback = $r->getStaticVariables()['callback']; + $e = new \TypeError(\sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); + } + if (\PHP_VERSION_ID < 70400) { + // leverage the ErrorHandler component with graceful fallback when it's not available + return \trigger_error($e, \E_USER_ERROR); + } + throw $e; + } catch (\Error $e) { + if (\TypeError::class === \get_class($e) && __FILE__ === $e->getFile()) { + $type = \explode(', ', $e->getMessage()); + $type = \substr(\array_pop($type), 0, -\strlen(' returned')); + $r = new \ReflectionFunction($this->value); + $callback = $r->getStaticVariables()['callback']; + $e = new \TypeError(\sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); + } + if (\PHP_VERSION_ID < 70400) { + // leverage the ErrorHandler component with graceful fallback when it's not available + return \trigger_error($e, \E_USER_ERROR); + } + throw $e; + } + } + public function __sleep() + { + $this->__toString(); + $phabelReturn = ['value']; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function jsonSerialize() + { + $phabelReturn = $this->__toString(); + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + private function __construct() + { + } + private static function getPrettyName(callable $callback) + { + if (\is_string($callback)) { + $phabelReturn = $callback; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + if (\is_array($callback)) { + $class = \is_object($callback[0]) ? \get_debug_type($callback[0]) : $callback[0]; + $method = $callback[1]; + } elseif ($callback instanceof \Closure) { + $r = new \ReflectionFunction($callback); + if (\false !== \strpos($r->name, '{closure}') || !($class = $r->getClosureScopeClass())) { + $phabelReturn = $r->name; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } + $class = $class->name; + $method = $r->name; + } else { + $class = \get_debug_type($callback); + $method = '__invoke'; + } + $phabelReturn = $class . '::' . $method; + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/string/Resources/data/wcswidth_table_wide.php b/vendor-bundle/symfony/string/Resources/data/wcswidth_table_wide.php new file mode 100644 index 000000000..832c94f74 --- /dev/null +++ b/vendor-bundle/symfony/string/Resources/data/wcswidth_table_wide.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String; + +if (!\function_exists(u::class)) { + function u($string = '') + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + $phabelReturn = new UnicodeString(isset($string) ? $string : ''); + if (!$phabelReturn instanceof UnicodeString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type UnicodeString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} +if (!\function_exists(b::class)) { + function b($string = '') + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + $phabelReturn = new ByteString(isset($string) ? $string : ''); + if (!$phabelReturn instanceof ByteString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ByteString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} +if (!\function_exists(s::class)) { + /** + * @return UnicodeString|ByteString + */ + function s($string = '') + { + if (!\is_null($string)) { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + } + $string = isset($string) ? $string : ''; + $phabelReturn = \preg_match('//u', $string) ? new UnicodeString($string) : new ByteString($string); + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/string/Slugger/AsciiSlugger.php b/vendor-bundle/symfony/string/Slugger/AsciiSlugger.php new file mode 100644 index 000000000..8f3cb9e59 --- /dev/null +++ b/vendor-bundle/symfony/string/Slugger/AsciiSlugger.php @@ -0,0 +1,226 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String\Slugger; + +use Phabel\Symfony\Component\String\AbstractUnicodeString; +use Phabel\Symfony\Component\String\UnicodeString; +use Phabel\Symfony\Contracts\Translation\LocaleAwareInterface; +if (!\interface_exists(LocaleAwareInterface::class)) { + throw new \LogicException('You cannot use the "Symfony\\Component\\String\\Slugger\\AsciiSlugger" as the "symfony/translation-contracts" package is not installed. Try running "composer require symfony/translation-contracts".'); +} +/** + * @author Titouan Galopin + */ +class AsciiSlugger implements SluggerInterface, LocaleAwareInterface +{ + const LOCALE_TO_TRANSLITERATOR_ID = ['am' => 'Amharic-Latin', 'ar' => 'Arabic-Latin', 'az' => 'Azerbaijani-Latin', 'be' => 'Belarusian-Latin', 'bg' => 'Bulgarian-Latin', 'bn' => 'Bengali-Latin', 'de' => 'de-ASCII', 'el' => 'Greek-Latin', 'fa' => 'Persian-Latin', 'he' => 'Hebrew-Latin', 'hy' => 'Armenian-Latin', 'ka' => 'Georgian-Latin', 'kk' => 'Kazakh-Latin', 'ky' => 'Kirghiz-Latin', 'ko' => 'Korean-Latin', 'mk' => 'Macedonian-Latin', 'mn' => 'Mongolian-Latin', 'or' => 'Oriya-Latin', 'ps' => 'Pashto-Latin', 'ru' => 'Russian-Latin', 'sr' => 'Serbian-Latin', 'sr_Cyrl' => 'Serbian-Latin', 'th' => 'Thai-Latin', 'tk' => 'Turkmen-Latin', 'uk' => 'Ukrainian-Latin', 'uz' => 'Uzbek-Latin', 'zh' => 'Han-Latin']; + private $defaultLocale; + private $symbolsMap = ['en' => ['@' => 'at', '&' => 'and']]; + /** + * Cache of transliterators per locale. + * + * @var \Transliterator[] + */ + private $transliterators = []; + /** + * @param array|\Closure|null $symbolsMap + */ + public function __construct($defaultLocale = null, $symbolsMap = null) + { + if (!\is_null($defaultLocale)) { + if (!\is_string($defaultLocale)) { + if (!(\is_string($defaultLocale) || \is_object($defaultLocale) && \method_exists($defaultLocale, '__toString') || (\is_bool($defaultLocale) || \is_numeric($defaultLocale)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($defaultLocale) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($defaultLocale) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $defaultLocale = (string) $defaultLocale; + } + } + } + if (null !== $symbolsMap && !\is_array($symbolsMap) && !$symbolsMap instanceof \Closure) { + throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be array, Closure or null, "%s" given.', __METHOD__, \gettype($symbolsMap))); + } + $this->defaultLocale = $defaultLocale; + $this->symbolsMap = isset($symbolsMap) ? $symbolsMap : $this->symbolsMap; + } + /** + * {@inheritdoc} + */ + public function setLocale($locale) + { + $this->defaultLocale = $locale; + } + /** + * {@inheritdoc} + */ + public function getLocale() + { + return $this->defaultLocale; + } + /** + * {@inheritdoc} + */ + public function slug($string, $separator = '-', $locale = null) + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + if (!\is_string($separator)) { + if (!(\is_string($separator) || \is_object($separator) && \method_exists($separator, '__toString') || (\is_bool($separator) || \is_numeric($separator)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($separator) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($separator) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $separator = (string) $separator; + } + } + if (!\is_null($locale)) { + if (!\is_string($locale)) { + if (!(\is_string($locale) || \is_object($locale) && \method_exists($locale, '__toString') || (\is_bool($locale) || \is_numeric($locale)))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($locale) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($locale) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $locale = (string) $locale; + } + } + } + $locale = isset($locale) ? $locale : $this->defaultLocale; + $transliterator = []; + if ($locale && ('de' === $locale || 0 === \strpos($locale, 'de_'))) { + // Use the shortcut for German in UnicodeString::ascii() if possible (faster and no requirement on intl) + $transliterator = ['de-ASCII']; + } elseif (\function_exists('transliterator_transliterate') && $locale) { + $transliterator = (array) $this->createTransliterator($locale); + } + if ($this->symbolsMap instanceof \Closure) { + // If the symbols map is passed as a closure, there is no need to fallback to the parent locale + // as the closure can just provide substitutions for all locales of interest. + $symbolsMap = $this->symbolsMap; + \array_unshift($transliterator, static function ($s) use($symbolsMap, $locale) { + return $symbolsMap($s, $locale); + }); + } + $unicodeString = (new UnicodeString($string))->ascii($transliterator); + if (\is_array($this->symbolsMap)) { + $map = null; + if (isset($this->symbolsMap[$locale])) { + $map = $this->symbolsMap[$locale]; + } else { + $parent = self::getParentLocale($locale); + if ($parent && isset($this->symbolsMap[$parent])) { + $map = $this->symbolsMap[$parent]; + } + } + if ($map) { + foreach ($map as $char => $replace) { + $unicodeString = $unicodeString->replace($char, ' ' . $replace . ' '); + } + } + } + $phabelReturn = $unicodeString->replaceMatches('/[^A-Za-z0-9]++/', $separator)->trim($separator); + if (!$phabelReturn instanceof AbstractUnicodeString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractUnicodeString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private function createTransliterator($locale) + { + if (!\is_string($locale)) { + if (!(\is_string($locale) || \is_object($locale) && \method_exists($locale, '__toString') || (\is_bool($locale) || \is_numeric($locale)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($locale) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($locale) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $locale = (string) $locale; + } + } + if (\array_key_exists($locale, $this->transliterators)) { + $phabelReturn = $this->transliterators[$locale]; + if (!($phabelReturn instanceof \Transliterator || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Transliterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + // Exact locale supported, cache and return + if ($id = isset(self::LOCALE_TO_TRANSLITERATOR_ID[$locale]) ? self::LOCALE_TO_TRANSLITERATOR_ID[$locale] : null) { + $phabelReturn = $this->transliterators[$locale] = NULL !== ($phabel_2a153f4ebbeff1bb = \Transliterator::create($id . '/BGN')) ? $phabel_2a153f4ebbeff1bb : \Transliterator::create($id); + if (!($phabelReturn instanceof \Transliterator || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Transliterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + // Locale not supported and no parent, fallback to any-latin + if (!($parent = self::getParentLocale($locale))) { + $phabelReturn = $this->transliterators[$locale] = null; + if (!($phabelReturn instanceof \Transliterator || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Transliterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + // Try to use the parent locale (ie. try "de" for "de_AT") and cache both locales + if ($id = isset(self::LOCALE_TO_TRANSLITERATOR_ID[$parent]) ? self::LOCALE_TO_TRANSLITERATOR_ID[$parent] : null) { + $transliterator = NULL !== ($phabel_989761a0df0962b2 = \Transliterator::create($id . '/BGN')) ? $phabel_989761a0df0962b2 : \Transliterator::create($id); + } + $phabelReturn = $this->transliterators[$locale] = $this->transliterators[$parent] = isset($transliterator) ? $transliterator : null; + if (!($phabelReturn instanceof \Transliterator || \is_null($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?Transliterator, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + private static function getParentLocale($locale) + { + if (!\is_null($locale)) { + if (!\is_string($locale)) { + if (!(\is_string($locale) || \is_object($locale) && \method_exists($locale, '__toString') || (\is_bool($locale) || \is_numeric($locale)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($locale) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($locale) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $locale = (string) $locale; + } + } + } + if (!$locale) { + $phabelReturn = null; + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } + if (\false === ($str = \strrchr($locale, '_'))) { + $phabelReturn = null; + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + // no parent locale + return $phabelReturn; + } + $phabelReturn = \substr($locale, 0, -\strlen($str)); + if (!\is_null($phabelReturn)) { + if (!\is_string($phabelReturn)) { + if (!(\is_string($phabelReturn) || \is_object($phabelReturn) && \method_exists($phabelReturn, '__toString') || (\is_bool($phabelReturn) || \is_numeric($phabelReturn)))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (string) $phabelReturn; + } + } + } + return $phabelReturn; + } +} diff --git a/vendor-bundle/symfony/string/Slugger/SluggerInterface.php b/vendor-bundle/symfony/string/Slugger/SluggerInterface.php new file mode 100644 index 000000000..f5c293c2a --- /dev/null +++ b/vendor-bundle/symfony/string/Slugger/SluggerInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String\Slugger; + +use Phabel\Symfony\Component\String\AbstractUnicodeString; +/** + * Creates a URL-friendly slug from a given string. + * + * @author Titouan Galopin + */ +interface SluggerInterface +{ + /** + * Creates a slug for the given string and locale, using appropriate transliteration when needed. + */ + public function slug($string, $separator = '-', $locale = null); +} diff --git a/vendor-bundle/symfony/string/UnicodeString.php b/vendor-bundle/symfony/string/UnicodeString.php new file mode 100644 index 000000000..af321cc5e --- /dev/null +++ b/vendor-bundle/symfony/string/UnicodeString.php @@ -0,0 +1,663 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Phabel\Symfony\Component\String; + +use Phabel\Symfony\Component\String\Exception\ExceptionInterface; +use Phabel\Symfony\Component\String\Exception\InvalidArgumentException; +/** + * Represents a string of Unicode grapheme clusters encoded as UTF-8. + * + * A letter followed by combining characters (accents typically) form what Unicode defines + * as a grapheme cluster: a character as humans mean it in written texts. This class knows + * about the concept and won't split a letter apart from its combining accents. It also + * ensures all string comparisons happen on their canonically-composed representation, + * ignoring e.g. the order in which accents are listed when a letter has many of them. + * + * @see https://unicode.org/reports/tr15/ + * + * @author Nicolas Grekas + * @author Hugo Hamon + * + * @throws ExceptionInterface + */ +class UnicodeString extends AbstractUnicodeString +{ + public function __construct($string = '') + { + if (!\is_string($string)) { + if (!(\is_string($string) || \is_object($string) && \method_exists($string, '__toString') || (\is_bool($string) || \is_numeric($string)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($string) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($string) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $string = (string) $string; + } + } + $this->string = \normalizer_is_normalized($string) ? $string : \normalizer_normalize($string); + if (\false === $this->string) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + } + public function append(...$suffix) + { + foreach ($suffix as $phabelVariadicIndex => $phabelVariadic) { + if (!\is_string($phabelVariadic)) { + if (!(\is_string($phabelVariadic) || \is_object($phabelVariadic) && \method_exists($phabelVariadic, '__toString') || (\is_bool($phabelVariadic) || \is_numeric($phabelVariadic)))) { + throw new \TypeError(__METHOD__ . '(): Argument #' . (1 + $phabelVariadicIndex) . ' must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($suffix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelVariadic = (string) $phabelVariadic; + } + } + } + $str = clone $this; + $str->string = $this->string . (1 >= \count($suffix) ? isset($suffix[0]) ? $suffix[0] : '' : \implode('', $suffix)); + \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); + if (\false === $str->string) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function chunk($length = 1) + { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($length) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + if (1 > $length) { + throw new InvalidArgumentException('The chunk length must be greater than zero.'); + } + if ('' === $this->string) { + $phabelReturn = []; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + $rx = '/('; + while (65535 < $length) { + $rx .= '\\X{65535}'; + $length -= 65535; + } + $rx .= '\\X{' . $length . '})/u'; + $str = clone $this; + $chunks = []; + foreach (\preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) { + $str->string = $chunk; + $chunks[] = clone $str; + } + $phabelReturn = $chunks; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function endsWith($suffix) + { + if ($suffix instanceof AbstractString) { + $suffix = $suffix->string; + } elseif (\is_array($suffix) || $suffix instanceof \Traversable) { + $phabelReturn = parent::endsWith($suffix); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } else { + $suffix = (string) $suffix; + } + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + \normalizer_is_normalized($suffix, $form) ?: ($suffix = \normalizer_normalize($suffix, $form)); + if ('' === $suffix || \false === $suffix) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if ($this->ignoreCase) { + $phabelReturn = 0 === \mb_stripos(\grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)), $suffix, 0, 'UTF-8'); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = $suffix === \grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function equalsTo($string) + { + if ($string instanceof AbstractString) { + $string = $string->string; + } elseif (\is_array($string) || $string instanceof \Traversable) { + $phabelReturn = parent::equalsTo($string); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } else { + $string = (string) $string; + } + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + \normalizer_is_normalized($string, $form) ?: ($string = \normalizer_normalize($string, $form)); + if ('' !== $string && \false !== $string && $this->ignoreCase) { + $phabelReturn = \strlen($string) === \strlen($this->string) && 0 === \mb_stripos($this->string, $string, 0, 'UTF-8'); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = $string === $this->string; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function indexOf($needle, $offset = 0) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (\is_array($needle) || $needle instanceof \Traversable) { + $phabelReturn = parent::indexOf($needle, $offset); + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } else { + $needle = (string) $needle; + } + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + \normalizer_is_normalized($needle, $form) ?: ($needle = \normalizer_normalize($needle, $form)); + if ('' === $needle || \false === $needle) { + $phabelReturn = null; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + try { + $i = $this->ignoreCase ? \grapheme_stripos($this->string, $needle, $offset) : \grapheme_strpos($this->string, $needle, $offset); + } catch (\ValueError $e) { + $phabelReturn = null; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + $phabelReturn = \false === $i ? null : $i; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + public function indexOfLast($needle, $offset = 0) + { + if (!\is_int($offset)) { + if (!(\is_bool($offset) || \is_numeric($offset))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($offset) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($offset) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $offset = (int) $offset; + } + } + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (\is_array($needle) || $needle instanceof \Traversable) { + $phabelReturn = parent::indexOfLast($needle, $offset); + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } else { + $needle = (string) $needle; + } + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + \normalizer_is_normalized($needle, $form) ?: ($needle = \normalizer_normalize($needle, $form)); + if ('' === $needle || \false === $needle) { + $phabelReturn = null; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + $string = $this->string; + if (0 > $offset) { + // workaround https://bugs.php.net/74264 + if (0 > ($offset += \grapheme_strlen($needle))) { + $string = \grapheme_substr($string, 0, $offset); + } + $offset = 0; + } + $i = $this->ignoreCase ? \grapheme_strripos($string, $needle, $offset) : \grapheme_strrpos($string, $needle, $offset); + $phabelReturn = \false === $i ? null : $i; + if (!\is_null($phabelReturn)) { + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + } + return $phabelReturn; + } + public function join(array $strings, $lastGlue = null) + { + if (!\is_null($lastGlue)) { + if (!\is_string($lastGlue)) { + if (!(\is_string($lastGlue) || \is_object($lastGlue) && \method_exists($lastGlue, '__toString') || (\is_bool($lastGlue) || \is_numeric($lastGlue)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($lastGlue) must be of type ?string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($lastGlue) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $lastGlue = (string) $lastGlue; + } + } + } + $str = parent::join($strings, $lastGlue); + \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function length() + { + $phabelReturn = \grapheme_strlen($this->string); + if (!\is_int($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (int) $phabelReturn; + } + } + return $phabelReturn; + } + /** + * @return static + */ + public function normalize($form = self::NFC) + { + if (!\is_int($form)) { + if (!(\is_bool($form) || \is_numeric($form))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($form) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($form) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $form = (int) $form; + } + } + $str = clone $this; + if (\in_array($form, [self::NFC, self::NFKC], \true)) { + \normalizer_is_normalized($str->string, $form) ?: ($str->string = \normalizer_normalize($str->string, $form)); + } elseif (!\in_array($form, [self::NFD, self::NFKD], \true)) { + throw new InvalidArgumentException('Unsupported normalization form.'); + } elseif (!\normalizer_is_normalized($str->string, $form)) { + $str->string = \normalizer_normalize($str->string, $form); + $str->ignoreCase = null; + } + $phabelReturn = $str; + if (!$phabelReturn instanceof parent) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type ' . parent::class . ', ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function prepend(...$prefix) + { + foreach ($prefix as $phabelVariadicIndex => $phabelVariadic) { + if (!\is_string($phabelVariadic)) { + if (!(\is_string($phabelVariadic) || \is_object($phabelVariadic) && \method_exists($phabelVariadic, '__toString') || (\is_bool($phabelVariadic) || \is_numeric($phabelVariadic)))) { + throw new \TypeError(__METHOD__ . '(): Argument #' . (1 + $phabelVariadicIndex) . ' must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($prefix) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelVariadic = (string) $phabelVariadic; + } + } + } + $str = clone $this; + $str->string = (1 >= \count($prefix) ? isset($prefix[0]) ? $prefix[0] : '' : \implode('', $prefix)) . $this->string; + \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); + if (\false === $str->string) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function replace($from, $to) + { + if (!\is_string($from)) { + if (!(\is_string($from) || \is_object($from) && \method_exists($from, '__toString') || (\is_bool($from) || \is_numeric($from)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($from) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($from) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $from = (string) $from; + } + } + if (!\is_string($to)) { + if (!(\is_string($to) || \is_object($to) && \method_exists($to, '__toString') || (\is_bool($to) || \is_numeric($to)))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($to) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($to) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $to = (string) $to; + } + } + $str = clone $this; + \normalizer_is_normalized($from) ?: ($from = \normalizer_normalize($from)); + if ('' !== $from && \false !== $from) { + $tail = $str->string; + $result = ''; + $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos'; + while ('' !== $tail && \false !== ($i = $indexOf($tail, $from))) { + $slice = \grapheme_substr($tail, 0, $i); + $result .= $slice . $to; + $tail = \substr($tail, \strlen($slice) + \strlen($from)); + } + $str->string = $result . $tail; + \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); + if (\false === $str->string) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + } + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function replaceMatches($fromRegexp, $to) + { + if (!\is_string($fromRegexp)) { + if (!(\is_string($fromRegexp) || \is_object($fromRegexp) && \method_exists($fromRegexp, '__toString') || (\is_bool($fromRegexp) || \is_numeric($fromRegexp)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($fromRegexp) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($fromRegexp) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $fromRegexp = (string) $fromRegexp; + } + } + $str = parent::replaceMatches($fromRegexp, $to); + \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function slice($start = 0, $length = null) + { + if (!\is_int($start)) { + if (!(\is_bool($start) || \is_numeric($start))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($start) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($start) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $start = (int) $start; + } + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + } + $str = clone $this; + if (\PHP_VERSION_ID < 80000 && 0 > $start && \grapheme_strlen($this->string) < -$start) { + $start = 0; + } + $str->string = (string) \grapheme_substr($this->string, $start, isset($length) ? $length : 2147483647); + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function splice($replacement, $start = 0, $length = null) + { + if (!\is_string($replacement)) { + if (!(\is_string($replacement) || \is_object($replacement) && \method_exists($replacement, '__toString') || (\is_bool($replacement) || \is_numeric($replacement)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($replacement) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($replacement) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $replacement = (string) $replacement; + } + } + if (!\is_int($start)) { + if (!(\is_bool($start) || \is_numeric($start))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($start) must be of type int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($start) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $start = (int) $start; + } + } + if (!\is_null($length)) { + if (!\is_int($length)) { + if (!(\is_bool($length) || \is_numeric($length))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($length) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($length) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $length = (int) $length; + } + } + } + $str = clone $this; + if (\PHP_VERSION_ID < 80000 && 0 > $start && \grapheme_strlen($this->string) < -$start) { + $start = 0; + } + $start = $start ? \strlen(\grapheme_substr($this->string, 0, $start)) : 0; + $length = $length ? \strlen(\grapheme_substr($this->string, $start, isset($length) ? $length : 2147483647)) : $length; + $str->string = \substr_replace($this->string, $replacement, $start, isset($length) ? $length : 2147483647); + \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); + if (\false === $str->string) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $phabelReturn = $str; + if (!$phabelReturn instanceof AbstractString) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type AbstractString, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function split($delimiter, $limit = null, $flags = null) + { + if (!\is_string($delimiter)) { + if (!(\is_string($delimiter) || \is_object($delimiter) && \method_exists($delimiter, '__toString') || (\is_bool($delimiter) || \is_numeric($delimiter)))) { + throw new \TypeError(__METHOD__ . '(): Argument #1 ($delimiter) must be of type string, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($delimiter) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $delimiter = (string) $delimiter; + } + } + if (!\is_null($limit)) { + if (!\is_int($limit)) { + if (!(\is_bool($limit) || \is_numeric($limit))) { + throw new \TypeError(__METHOD__ . '(): Argument #2 ($limit) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($limit) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $limit = (int) $limit; + } + } + } + if (!\is_null($flags)) { + if (!\is_int($flags)) { + if (!(\is_bool($flags) || \is_numeric($flags))) { + throw new \TypeError(__METHOD__ . '(): Argument #3 ($flags) must be of type ?int, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($flags) . ' given, called in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $flags = (int) $flags; + } + } + } + if (1 > ($limit = isset($limit) ? $limit : 2147483647)) { + throw new InvalidArgumentException('Split limit must be a positive integer.'); + } + if ('' === $delimiter) { + throw new InvalidArgumentException('Split delimiter is empty.'); + } + if (null !== $flags) { + $phabelReturn = parent::split($delimiter . 'u', $limit, $flags); + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + \normalizer_is_normalized($delimiter) ?: ($delimiter = \normalizer_normalize($delimiter)); + if (\false === $delimiter) { + throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.'); + } + $str = clone $this; + $tail = $this->string; + $chunks = []; + $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos'; + while (1 < $limit && \false !== ($i = $indexOf($tail, $delimiter))) { + $str->string = \grapheme_substr($tail, 0, $i); + $chunks[] = clone $str; + $tail = \substr($tail, \strlen($str->string) + \strlen($delimiter)); + --$limit; + } + $str->string = $tail; + $chunks[] = clone $str; + $phabelReturn = $chunks; + if (!\is_array($phabelReturn)) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type array, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } + return $phabelReturn; + } + public function startsWith($prefix) + { + if ($prefix instanceof AbstractString) { + $prefix = $prefix->string; + } elseif (\is_array($prefix) || $prefix instanceof \Traversable) { + $phabelReturn = parent::startsWith($prefix); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } else { + $prefix = (string) $prefix; + } + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + \normalizer_is_normalized($prefix, $form) ?: ($prefix = \normalizer_normalize($prefix, $form)); + if ('' === $prefix || \false === $prefix) { + $phabelReturn = \false; + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + if ($this->ignoreCase) { + $phabelReturn = 0 === \mb_stripos(\grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES), $prefix, 0, 'UTF-8'); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + $phabelReturn = $prefix === \grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES); + if (!\is_bool($phabelReturn)) { + if (!(\is_bool($phabelReturn) || \is_numeric($phabelReturn) || \is_string($phabelReturn))) { + throw new \TypeError(__METHOD__ . '(): Return value must be of type bool, ' . \Phabel\Plugin\TypeHintReplacer::getDebugType($phabelReturn) . ' returned in ' . \Phabel\Plugin\TypeHintReplacer::trace()); + } else { + $phabelReturn = (bool) $phabelReturn; + } + } + return $phabelReturn; + } + public function __wakeup() + { + if (!\is_string($this->string)) { + throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__); + } + \normalizer_is_normalized($this->string) ?: ($this->string = \normalizer_normalize($this->string)); + } + public function __clone() + { + if (null === $this->ignoreCase) { + \normalizer_is_normalized($this->string) ?: ($this->string = \normalizer_normalize($this->string)); + } + $this->ignoreCase = \false; + } +}