Fix windows

pull/41/head
韩天峰 4 weeks ago
parent 606819a8ad
commit 89e58350a8
  1. 18
      examples/tetris-win32/main.php
  2. 21
      phpunit/src/ConstantExpressionValidatorTest.php
  3. 7
      src/Preprocessor.php
  4. 20
      src/Transform/ConstantExpressionValidationVisitor.php
  5. 6
      src/Transform/ConstantExpressionValidator.php
  6. 26
      src/Transform/Visitor.php
  7. 5
      src/Translator.php
  8. 1
      tests/compiler/array/array-push-empty-unpack.phpt

@ -42,8 +42,8 @@ function rgb(int $r, int $g, int $b): int
}
// Piece colors
const COLOR_CYAN = 0x00FFFF; // I
const COLOR_YELLOW = 0x00FFFF; // O - will override below
const COLOR_CYAN = 0xFFFF00; // I
const COLOR_YELLOW = 0x00FFFF; // O
const COLOR_PURPLE = 0x800080; // T
const COLOR_GREEN = 0x00FF00; // S
const COLOR_RED = 0x0000FF; // Z
@ -51,13 +51,13 @@ const COLOR_BLUE = 0xFF0000; // J
const COLOR_ORANGE = 0x00A5FF; // L
const PIECE_COLORS = [
rgb(0, 255, 255), // I - Cyan
rgb(255, 255, 0), // O - Yellow
rgb(128, 0, 128), // T - Purple
rgb(0, 255, 0), // S - Green
rgb(255, 0, 0), // Z - Red
rgb(0, 0, 255), // J - Blue
rgb(255, 165, 0), // L - Orange
COLOR_CYAN,
COLOR_YELLOW,
COLOR_PURPLE,
COLOR_GREEN,
COLOR_RED,
COLOR_BLUE,
COLOR_ORANGE,
];
// 7 tetromino shapes (4 rotations each, 4x4 grid) - defined in PHP!

@ -258,6 +258,27 @@ final class ConstantExpressionValidatorTest extends PHPUnit\Framework\TestCase
));
}
public function testCompilerBoundaryRoutesUnsupportedSyntaxThroughFatalDiagnostic(): void
{
$parser = (new ParserFactory())->createForVersion(PhpVersion::fromString('8.5'));
$statements = $parser->parse("<?php\nconst VALUE = loadValue();");
self::assertNotNull($statements);
$traverser = new NodeTraverser();
$traverser->addVisitor(new ConstantExpressionValidationVisitor(
'8.5',
static function (Node $node, string $message): never {
throw new \RuntimeException("fatal: {$message} at line {$node->getStartLine()}");
},
));
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage(
'fatal: Constant expression contains invalid operations at line 2',
);
$traverser->traverse($statements);
}
private function parseAttributeExpression(string $expression, string $phpVersion): Node\Expr
{
return $this->parseAttributeArguments($expression, $phpVersion)[0]->value;

@ -40,7 +40,7 @@ use PhpParser\NodeVisitor\NameResolver;
class Preprocessor extends CompilerBase
{
protected function getSortedFiles(array $list): array
public function getSortedFiles(array $list): array
{
$sorter = new StringSort();
$fileDeps = [];
@ -149,7 +149,10 @@ class Preprocessor extends CompilerBase
fn (Node $node, string $message) => $this->warning($node, $message),
$this->file,
));
$traverser->addVisitor(new ConstantExpressionValidationVisitor($this->phpVersion));
$traverser->addVisitor(new ConstantExpressionValidationVisitor(
$this->phpVersion,
fn (Node $node, string $message) => $this->fatalError($node, $message),
));
$traverser->addVisitor(new RuntimeAttributeFactoryLowering($this->file));
$stmts = $traverser->traverse($ast);

@ -8,8 +8,10 @@
namespace TypePhp\Transform;
use Closure;
use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;
use TypePhp\Exception\SyntaxError;
/**
* Applies the allow_dynamic values used by php-src at each declaration site.
@ -26,13 +28,29 @@ final class ConstantExpressionValidationVisitor extends NodeVisitorAbstract
private readonly bool $supportsDynamicStaticInitializers;
public function __construct(string $phpVersion)
/** @param null|Closure(Node, string): never $fatalError */
public function __construct(
string $phpVersion,
private readonly ?Closure $fatalError = null,
)
{
$this->validator = new ConstantExpressionValidator($phpVersion);
$this->supportsDynamicStaticInitializers = version_compare($phpVersion, '8.3', '>=');
}
public function enterNode(Node $node): null
{
try {
return $this->validateNode($node);
} catch (SyntaxError $error) {
if ($this->fatalError !== null) {
($this->fatalError)($node, $error->getMessage());
}
throw $error;
}
}
private function validateNode(Node $node): null
{
if ($node instanceof Node\Attribute) {
$this->validator->validateArguments(

@ -321,7 +321,11 @@ final class ConstantExpressionValidator
private function tryEvaluate(Expr $expression): array
{
try {
$value = (new ConstExprEvaluator())->evaluateDirectly($expression);
$value = (new ConstExprEvaluator(
static function (): never {
throw new \LogicException('Expression is not statically known');
},
))->evaluateDirectly($expression);
return [true, $value];
} catch (\Throwable) {
return [false, null];

@ -54,16 +54,22 @@ class Visitor extends NodeVisitorAbstract
$classReadonly = $node instanceof Stmt\Class_ && $node->isReadonly();
foreach ($node->stmts as $stmt) {
if ($stmt instanceof Stmt\Property) {
array_push($methods, ...PropertyHookLowering::lowerProperty($stmt));
array_push($methods, ...$this->guard(
foreach (PropertyHookLowering::lowerProperty($stmt) as $method) {
$methods[] = $method;
}
foreach ($this->guard(
$stmt,
static fn () => GetterLowering::lowerProperty($stmt),
'Getter',
));
array_push($methods, ...$this->guard(
) as $method) {
$methods[] = $method;
}
foreach ($this->guard(
$stmt,
static fn () => PropertyMethodLowering::lowerProperty($stmt, $classReadonly),
));
) as $method) {
$methods[] = $method;
}
} elseif ($stmt instanceof Stmt\ClassMethod && $stmt->name->toLowerString() === '__construct') {
foreach ($stmt->params as $param) {
$marker = PropertyHookLowering::lowerPromotedProperty($param);
@ -78,15 +84,19 @@ class Visitor extends NodeVisitorAbstract
if ($getter !== null) {
$methods[] = $getter;
}
array_push($methods, ...$this->guard(
foreach ($this->guard(
$param,
static fn () => PropertyMethodLowering::lowerPromotedProperty($param, $classReadonly),
));
) as $method) {
$methods[] = $method;
}
}
}
}
if ($methods !== []) {
array_push($node->stmts, ...$methods);
foreach ($methods as $method) {
$node->stmts[] = $method;
}
}
$this->guard($node, static fn () => ConstructorLowering::lowerClassLike($node), 'Constructor');
if ($node instanceof Stmt\Class_) {

@ -2313,7 +2313,10 @@ CODE;
$traverser = new NodeTraverser();
$traverser->addVisitor(new NameResolver(null, ['replaceNodes' => false]));
$traverser->addVisitor(new Visitor(sourceFile: $this->file));
$traverser->addVisitor(new ConstantExpressionValidationVisitor($this->phpVersion));
$traverser->addVisitor(new ConstantExpressionValidationVisitor(
$this->phpVersion,
fn (Node $node, string $message) => $this->fatalError($node, $message),
));
$traverser->addVisitor(new RuntimeAttributeFactoryLowering($this->file));
$stmts = $traverser->traverse($ast);

@ -5,6 +5,7 @@ array_push retains its required array argument when an unpacked list is empty
function main(): void
{
// Keep the required by-reference argument before an empty unpack.
$values = [];
array_push($values, ...[]);
var_dump($values);

Loading…
Cancel
Save