diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index f74fc64b..4b849a00 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,7 +2,7 @@ ## Project overview -TypePHP is an ahead-of-time compiler that translates PHP source into C++, then compiles and links it into a native binary or a PHP extension. The primary entrypoint is `tpc`, which boots `src/compiler.php`; that drives `TypePhp\Translator` through a fixed pipeline: +TypePHP is a PHP native compilation project. Its `tpc` command is TypePHP Compiler (AOT), which translates PHP source into C++, then compiles and links it into a native binary or a PHP extension. The primary entrypoint boots `src/compiler.php`; that drives `TypePhp\Translator` through a fixed pipeline: 1. `prepare()` scans files, parses ASTs, collects symbols, and topologically sorts PHP files by cross-file symbol usage. 2. `convert()` turns PHP ASTs into generated `.cc` files while passing through native source files (`.cpp`, `.c`, `.s`, `.m`, `.mm`). diff --git a/CLAUDE.md b/CLAUDE.md index e9530b67..36ea56df 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -TypePHP is an AOT (Ahead-of-Time) compiler that translates PHP source code to C++, then compiles it with GCC/Clang/MSVC into native binaries. It supports Linux (primary), macOS, and Windows. +TypePHP is a PHP native compilation project. Its `tpc` command is TypePHP Compiler (AOT), which translates PHP source code to C++, then compiles it with GCC/Clang/MSVC into native binaries. It supports Linux (primary), macOS, and Windows. **Prerequisites**: PHP 8.2+, GCC 9+ (C++17), CMake 3.24+. The `swoole/phpx` extension must be compiled (see README.md). diff --git a/phpunit/src/NativePropertyTest.php b/phpunit/src/NativePropertyTest.php index 8d502984..2defc314 100644 --- a/phpunit/src/NativePropertyTest.php +++ b/phpunit/src/NativePropertyTest.php @@ -58,6 +58,19 @@ class NativePropertyTest extends \BaseTest $this->assertStringNotContainsString('box.attr(php_get_prop(0, _literal_strings[0], 0, _literal_strings[1]), true) +=', $code); } + public function testNativeIntPropertyAssignOpConvertsBitwiseNotClassConst(): void + { + try { + $outputFile = $this->compileNativeProperty('native-property-assign-op-class-const.php'); + } catch (TestError $e) { + $this->fail($e->getMessage()); + } + + $code = file_get_contents($outputFile); + $this->assertStringContainsString('php_aot_static_int_ref(this_.attr(', $code); + $this->assertStringContainsString('&= (~php::toInt(php::constant(', $code); + } + public function testNativePropertyWriteConvertsOnlyWhenTypesDiffer(): void { try { diff --git a/src/CompilerBase.php b/src/CompilerBase.php index 1be14458..7d525a36 100644 --- a/src/CompilerBase.php +++ b/src/CompilerBase.php @@ -4423,7 +4423,7 @@ class CompilerBase implements PropertyAccessContext return 'php::BigInt::bitNot(' . $this->parseExpr($expr->expr) . ')'; } $var = $this->parseIdentifier($expr->expr); - return '~' . $var; + return '~' . $this->convertIntExpr($var); } protected function parseIf(Node\Stmt\If_ $v): string diff --git a/src/Translator.php b/src/Translator.php index 1b6d3bdc..d5963932 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -39,7 +39,7 @@ use Symfony\Component\Yaml\Yaml; class Translator extends Preprocessor { public const string VERSION = '0.3.0'; - public const string APP_NAME = 'TypePHP'; + public const string APP_NAME = 'TypePHP Compiler (AOT)'; protected string $targetName = 'app'; protected array $sourceDirs = []; protected bool $verbose = false; @@ -1881,12 +1881,12 @@ CODE; $nativeConst = $this->findNativeClassConst($expr, $class, $name); if ($nativeConst and $expr->hasAttribute('nativeConst')) { $constDef = $expr->getAttribute('nativeConst'); - return $this->genCValue($constDef->valueExpr->value); + return $constDef->valueExpr->value; } if ($this->isInternalClass($class)) { $constName = $class . '::' . $name; if (defined($constName)) { - return $this->genCValue(constant($constName)); + return constant($constName); } } // Resolve enum case references. Enum cases are runtime objects; their @@ -1897,7 +1897,7 @@ CODE; $classDef = $this->getClass($class); if ($classDef->enum && array_key_exists($name, $classDef->enumCases)) { $caseValue = $classDef->enumCases[$name]; - return $this->genCValue($caseValue ?? $name); + return $caseValue ?? $name; } } $this->fatalError($expr, "Class constant `{$class}::{$name}` not found"); diff --git a/src/gen_stub.php b/src/gen_stub.php index 052e559a..733eb245 100755 --- a/src/gen_stub.php +++ b/src/gen_stub.php @@ -5019,9 +5019,7 @@ function parseFunctionLike( if ($param->default instanceof Expr\ClassConstFetch && $param->default->class->toLowerString() === "self") { $defaultValue = getTranslator()->getClassConstValue($func, $name->className->name, $param->default->name->name); - if (!is_string($defaultValue)) { - $defaultValue = var_export($defaultValue, true); - } + $defaultValue = var_export($defaultValue, true); } else { $defaultValue = $param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null; } diff --git a/tests/aot/object_property/native-int-property-assign.phpt b/tests/aot/object_property/native-int-property-assign.phpt index 6c438bdf..009fe342 100644 --- a/tests/aot/object_property/native-int-property-assign.phpt +++ b/tests/aot/object_property/native-int-property-assign.phpt @@ -1,7 +1,8 @@ --TEST-- -Native int property assignment converts RHS without explicit cast +Native int property assignment follows strict property type rules --FILE-- colStart = $idx % $numCols; $gi->colEnd = $gi->colStart + 1; - $gi->rowStart = $idx / $numCols; + try { + $gi->rowStart = $idx / $numCols; + } catch (TypeError $e) { + var_dump($e->getMessage()); + } + $gi->rowStart = intdiv($idx, $numCols); $gi->rowEnd = $gi->rowStart + 1; $gi->w = $cols[$gi->colStart]->size; $gi->h = $gi->rowStart < count($rows) ? $rows[$gi->rowStart]->size : 50; @@ -53,6 +59,7 @@ function main(): void } ?> --EXPECT-- +string(63) "Cannot assign float to property GridItem::$rowStart of type int" int(2) int(3) int(1)