TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
74 lines
3.4 KiB
74 lines
3.4 KiB
<?php
|
|
|
|
use PHPUnit\Framework\Attributes\DataProvider;
|
|
use TypePhp\CompilerTest;
|
|
use TypePhp\Exception\SyntaxError;
|
|
use TypePhp\Exception\TestError;
|
|
|
|
final class StdContainerValueInitializerTest extends BaseTest
|
|
{
|
|
private function translate(string $source): string
|
|
{
|
|
global $translator;
|
|
$directory = sys_get_temp_dir() . '/std-value-initializer-' . bin2hex(random_bytes(6));
|
|
mkdir($directory);
|
|
$file = $directory . '/initializer.php';
|
|
file_put_contents($file, '<?php function main(): void { ' . $source . ' }');
|
|
try {
|
|
$translator = CompilerTest::create(TYPEPHP_ROOT_PATH);
|
|
$translator->addFiles([$file]);
|
|
$translator->prepareFile($file);
|
|
return file_get_contents($translator->convertFile($file));
|
|
} finally {
|
|
unlink($file);
|
|
rmdir($directory);
|
|
}
|
|
}
|
|
|
|
public function testEveryContainerAcceptsAnInferredArrayInitializer(): void
|
|
{
|
|
$code = $this->translate(<<<'PHP'
|
|
$n = 2;
|
|
$a = std::array([[1, $n], [3, 4]]);
|
|
$v = std::vector([1, $n]);
|
|
$m = std::map(['a' => 1, 'b' => $n]);
|
|
$o = std::orderedMap([1 => 'a', 2 => 'b']);
|
|
$l = std::list([1, $n]);
|
|
$d = std::dict(['a' => 1, 'b' => $n]);
|
|
PHP);
|
|
self::assertStringContainsString('php::StdArray<php::StdArray<php::Int, 2>, 2>', $code);
|
|
self::assertStringContainsString('a_ref.offsetGet(0).offsetSet(1, php::toInt(n))', $code);
|
|
self::assertStringContainsString('v_ref.push_back(php::toInt(n))', $code);
|
|
self::assertStringContainsString('m_ref.offsetSet(', $code);
|
|
self::assertStringContainsString('o_ref.offsetSet(', $code);
|
|
self::assertStringContainsString('l = php::Array{', $code);
|
|
self::assertStringContainsString('d = php::Array{', $code);
|
|
}
|
|
|
|
#[DataProvider('invalidInitializers')]
|
|
public function testInvalidInitializers(string $source, string $message): void
|
|
{
|
|
try {
|
|
$this->translate($source);
|
|
self::fail('Invalid std value initializer was accepted');
|
|
} catch (TestError|SyntaxError $error) {
|
|
self::assertStringContainsString($message, $error->getMessage());
|
|
}
|
|
}
|
|
|
|
public static function invalidInitializers(): iterable
|
|
{
|
|
yield 'empty' => ['$v = std::vector([]);', 'cannot infer types from an empty array'];
|
|
yield 'mixed values' => ['$v = std::vector([1, "2"]);', 'values must all have exactly the same type'];
|
|
yield 'mixed keys' => ['$m = std::map([1 => 1, "2" => 2]);', 'keys must all have exactly the same type'];
|
|
yield 'float key' => ['$m = std::map([1.5 => 1]);', 'statically known int or string type'];
|
|
yield 'bool key' => ['$m = std::map([true => 1]);', 'statically known int or string type'];
|
|
yield 'null key' => ['$m = std::map([null => 1]);', 'statically known int or string type'];
|
|
yield 'map missing key' => ['$m = std::map([1, 2]);', 'requires an explicit key'];
|
|
yield 'ragged array' => ['$a = std::array([[1], [2, 3]]);', 'uniform rectangular shape'];
|
|
yield 'list string key' => ['$l = std::list(["a" => 1]);', 'keys must have type int'];
|
|
yield 'dict missing key' => ['$d = std::dict([1, 2]);', 'requires an explicit key'];
|
|
yield 'dynamic key' => ['$key = std::any("a"); $d = std::dict([$key => 1]);', 'statically known int or string type'];
|
|
yield 'dynamic value' => ['$x = std::any(1); $l = std::list([$x]);', 'cannot infer an element type from var/any'];
|
|
}
|
|
}
|
|
|