diff --git a/docs/REFACTORING_PLAN.md b/docs/REFACTORING_PLAN.md index 78fbd490..a880a34d 100644 --- a/docs/REFACTORING_PLAN.md +++ b/docs/REFACTORING_PLAN.md @@ -1,5 +1,7 @@ # AOT 编译器核心重构计划 +> 针对 `Translator`、`CompilerBase`、`Preprocessor` 的下一阶段 OOA/OOD/OOP 重构,请以 [CORE_OOA_OOD_OOP_REFACTORING_PLAN.md](CORE_OOA_OOD_OOP_REFACTORING_PLAN.md) 为实施基线。本文档保留此前模块化重构的历史计划。 + ## 背景 当前 AOT 编译器核心类承担了过多职责,尤其是 `CompilerBase`、`Translator` 等类同时包含 AST 分发、类型推导、属性访问解析、调用解析、代码生成、诊断信息、上下文状态维护等逻辑。随着功能持续增加,这种结构会带来以下问题: diff --git a/phpunit/src/CompilerBaseApiTest.php b/phpunit/src/CompilerBaseApiTest.php index bf7057d8..e7cb9a3e 100644 --- a/phpunit/src/CompilerBaseApiTest.php +++ b/phpunit/src/CompilerBaseApiTest.php @@ -5,6 +5,7 @@ namespace TypePhp\Tests; use PHPUnit\Framework\TestCase; use TypePhp\CompilerTest; use TypePhp\CompilerBase; +use TypePhp\Type; use TypePhp\Exception\TestError; use TypePhp\Platform\Windows; @@ -159,26 +160,26 @@ class CompilerBaseApiTest extends TestCase public function testGetTypeFromZendTypeKnown(): void { - $this->assertEquals(CompilerBase::TYPE_INT, $this->compiler->getTypeFromZendType('int')); - $this->assertEquals(CompilerBase::TYPE_FLOAT, $this->compiler->getTypeFromZendType('float')); - $this->assertEquals(CompilerBase::TYPE_BOOL, $this->compiler->getTypeFromZendType('bool')); - $this->assertEquals(CompilerBase::TYPE_BOOL, $this->compiler->getTypeFromZendType('true')); - $this->assertEquals(CompilerBase::TYPE_BOOL, $this->compiler->getTypeFromZendType('false')); - $this->assertEquals(CompilerBase::TYPE_VOID, $this->compiler->getTypeFromZendType('void')); - $this->assertEquals(CompilerBase::TYPE_VOID, $this->compiler->getTypeFromZendType('never')); - $this->assertEquals(CompilerBase::TYPE_STR, $this->compiler->getTypeFromZendType('string')); - $this->assertEquals(CompilerBase::TYPE_ARRAY, $this->compiler->getTypeFromZendType('array')); - $this->assertEquals(CompilerBase::TYPE_OBJECT, $this->compiler->getTypeFromZendType('object')); - $this->assertEquals(CompilerBase::TYPE_VAR, $this->compiler->getTypeFromZendType('mixed')); - $this->assertEquals(CompilerBase::TYPE_VAR, $this->compiler->getTypeFromZendType('null')); - $this->assertEquals(CompilerBase::TYPE_VAR, $this->compiler->getTypeFromZendType('callable')); - $this->assertEquals(CompilerBase::TYPE_VAR, $this->compiler->getTypeFromZendType('iterable')); + $this->assertEquals(Type::INT, $this->compiler->getTypeFromZendType('int')); + $this->assertEquals(Type::FLOAT, $this->compiler->getTypeFromZendType('float')); + $this->assertEquals(Type::BOOL, $this->compiler->getTypeFromZendType('bool')); + $this->assertEquals(Type::BOOL, $this->compiler->getTypeFromZendType('true')); + $this->assertEquals(Type::BOOL, $this->compiler->getTypeFromZendType('false')); + $this->assertEquals(Type::VOID, $this->compiler->getTypeFromZendType('void')); + $this->assertEquals(Type::VOID, $this->compiler->getTypeFromZendType('never')); + $this->assertEquals(Type::STR, $this->compiler->getTypeFromZendType('string')); + $this->assertEquals(Type::ARRAY, $this->compiler->getTypeFromZendType('array')); + $this->assertEquals(Type::OBJECT, $this->compiler->getTypeFromZendType('object')); + $this->assertEquals(Type::VAR, $this->compiler->getTypeFromZendType('mixed')); + $this->assertEquals(Type::VAR, $this->compiler->getTypeFromZendType('null')); + $this->assertEquals(Type::VAR, $this->compiler->getTypeFromZendType('callable')); + $this->assertEquals(Type::VAR, $this->compiler->getTypeFromZendType('iterable')); } public function testGetTypeFromZendTypeUnknown(): void { - $this->assertEquals(CompilerBase::TYPE_VAR, $this->compiler->getTypeFromZendType('unknown_type')); - $this->assertEquals(CompilerBase::TYPE_VAR, $this->compiler->getTypeFromZendType('SomeClass')); + $this->assertEquals(Type::VAR, $this->compiler->getTypeFromZendType('unknown_type')); + $this->assertEquals(Type::VAR, $this->compiler->getTypeFromZendType('SomeClass')); } // ======================================================================== diff --git a/phpunit/src/Generator/UtilsTest.php b/phpunit/src/Generator/UtilsTest.php index cb79fc1c..b94a0468 100644 --- a/phpunit/src/Generator/UtilsTest.php +++ b/phpunit/src/Generator/UtilsTest.php @@ -2,9 +2,10 @@ namespace TypePhp\Tests\Generator; +use TypePhp\Type; + use PHPUnit\Framework\TestCase; use TypePhp\CompilerTest; -use TypePhp\CompilerBase; class UtilsTest extends TestCase { @@ -97,14 +98,14 @@ class UtilsTest extends TestCase public function testGenArray(): void { $result = $this->invokeMethod('genArray', ['1', '2', '3']); - $this->assertStringStartsWith(CompilerBase::TYPE_ARRAY . '{', $result); + $this->assertStringStartsWith(Type::ARRAY . '{', $result); $this->assertStringContainsString('1, 2, 3', $result); } public function testGenArrayEmpty(): void { $result = $this->invokeMethod('genArray', []); - $this->assertStringStartsWith(CompilerBase::TYPE_ARRAY . '{', $result); + $this->assertStringStartsWith(Type::ARRAY . '{', $result); } // ======================================================================== diff --git a/phpunit/src/SsaAnalysisTest.php b/phpunit/src/SsaAnalysisTest.php index 8e87baa8..89396f87 100644 --- a/phpunit/src/SsaAnalysisTest.php +++ b/phpunit/src/SsaAnalysisTest.php @@ -2,6 +2,8 @@ namespace TypePhp\Tests; +use TypePhp\Type; + use PHPUnit\Framework\TestCase; use TypePhp\Analysis\SsaBuilder; use TypePhp\Analysis\SsaFlags; @@ -9,7 +11,6 @@ use TypePhp\Analysis\SsaVar; use TypePhp\Analysis\SsaBlock; use TypePhp\Analysis\VarState; use TypePhp\Analysis\PiConstraint; -use TypePhp\CompilerBase; use TypePhp\CompilerTest; use TypePhp\Entity\ClassDef; use TypePhp\Entity\MethodDef; @@ -1075,7 +1076,7 @@ class SsaAnalysisTest extends TestCase } '); - $this->assertSame(CompilerBase::TYPE_INT, $locals['n'] ?? null); + $this->assertSame(Type::INT, $locals['n'] ?? null); } public function testLoopVarOptimizerNarrowsForCounterAndConstantBoundVar(): void @@ -1087,8 +1088,8 @@ class SsaAnalysisTest extends TestCase } '); - $this->assertSame(CompilerBase::TYPE_INT, $locals['i'] ?? null); - $this->assertSame(CompilerBase::TYPE_INT, $locals['n'] ?? null); + $this->assertSame(Type::INT, $locals['i'] ?? null); + $this->assertSame(Type::INT, $locals['n'] ?? null); } public function testLoopVarOptimizerNarrowsForCounterWithStrlenBound(): void @@ -1099,7 +1100,7 @@ class SsaAnalysisTest extends TestCase } '); - $this->assertSame(CompilerBase::TYPE_INT, $locals['i'] ?? null); + $this->assertSame(Type::INT, $locals['i'] ?? null); } public function testLoopVarOptimizerNarrowsForCounterWithGenericIntFunctionBound(): void @@ -1110,7 +1111,7 @@ class SsaAnalysisTest extends TestCase } '); - $this->assertSame(CompilerBase::TYPE_INT, $locals['i'] ?? null); + $this->assertSame(Type::INT, $locals['i'] ?? null); } public function testLoopVarOptimizerRejectsInclusiveGenericIntFunctionBound(): void @@ -1132,7 +1133,7 @@ class SsaAnalysisTest extends TestCase } '); - $this->assertSame(CompilerBase::TYPE_INT, $locals['i'] ?? null); + $this->assertSame(Type::INT, $locals['i'] ?? null); } public function testLoopVarOptimizerNarrowsDescendingCounterFromIntMethod(): void @@ -1143,7 +1144,7 @@ class SsaAnalysisTest extends TestCase } '); - $this->assertSame(CompilerBase::TYPE_INT, $locals['i'] ?? null); + $this->assertSame(Type::INT, $locals['i'] ?? null); } public function testLoopVarOptimizerRejectsBodyCounterMutation(): void @@ -1210,7 +1211,7 @@ class SsaAnalysisTest extends TestCase $ssaVar->definition = new Stmt\Expression($assign); $result = $this->invoke('detectSsaDefType', $ssaVar); - $this->assertEquals(CompilerBase::TYPE_INT, $result); + $this->assertEquals(Type::INT, $result); } public function testDetectSsaDefTypeFloatLiteral(): void @@ -1220,7 +1221,7 @@ class SsaAnalysisTest extends TestCase $ssaVar->definition = new Stmt\Expression($assign); $result = $this->invoke('detectSsaDefType', $ssaVar); - $this->assertEquals(CompilerBase::TYPE_FLOAT, $result); + $this->assertEquals(Type::FLOAT, $result); } public function testDetectSsaDefTypeStringLiteral(): void @@ -1230,7 +1231,7 @@ class SsaAnalysisTest extends TestCase $ssaVar->definition = new Stmt\Expression($assign); $result = $this->invoke('detectSsaDefType', $ssaVar); - $this->assertEquals(CompilerBase::TYPE_STR, $result); + $this->assertEquals(Type::STR, $result); } public function testDetectSsaDefTypeBoolLiteral(): void @@ -1240,15 +1241,15 @@ class SsaAnalysisTest extends TestCase $ssaVar->definition = new Stmt\Expression($assign); $result = $this->invoke('detectSsaDefType', $ssaVar); - $this->assertEquals(CompilerBase::TYPE_BOOL, $result); + $this->assertEquals(Type::BOOL, $result); } public function testDetectTypeOfExplicitStdNativeCalls(): void { $cases = [ - 'int' => CompilerBase::TYPE_INT, - 'float' => CompilerBase::TYPE_FLOAT, - 'bool' => CompilerBase::TYPE_BOOL, + 'int' => Type::INT, + 'float' => Type::FLOAT, + 'bool' => Type::BOOL, ]; foreach ($cases as $method => $expectedType) { @@ -1298,7 +1299,7 @@ class SsaAnalysisTest extends TestCase $ssaVar->definition = new Stmt\Expression($assignOp); $result = $this->invoke('detectSsaDefType', $ssaVar); - $this->assertEquals(CompilerBase::TYPE_FLOAT, $result); + $this->assertEquals(Type::FLOAT, $result); } public function testDetectSsaDefTypeAssignOpPlusIsUnknownForIntRhs(): void @@ -1330,7 +1331,7 @@ class SsaAnalysisTest extends TestCase $ssaVar->definition = new Stmt\Expression($assign); $result = $this->invoke('detectSsaDefType', $ssaVar); - $this->assertEquals(CompilerBase::TYPE_INT, $result); + $this->assertEquals(Type::INT, $result); } // ======================================================================== diff --git a/phpunit/src/TraitsTest.php b/phpunit/src/TraitsTest.php index 17d36541..ab4a7eaa 100644 --- a/phpunit/src/TraitsTest.php +++ b/phpunit/src/TraitsTest.php @@ -2,9 +2,10 @@ namespace TypePhp\Tests; +use TypePhp\Type; + use PHPUnit\Framework\TestCase; use TypePhp\CompilerTest; -use TypePhp\CompilerBase; use TypePhp\Entity\ArgInfo; class TraitsTest extends TestCase @@ -123,18 +124,18 @@ class TraitsTest extends TestCase public function testIsStdContainerTypeTrue(): void { - $this->assertTrue($this->invoke('isStdContainerType', CompilerBase::TYPE_STD_ARRAY)); - $this->assertTrue($this->invoke('isStdContainerType', CompilerBase::TYPE_STD_VECTOR)); - $this->assertTrue($this->invoke('isStdContainerType', CompilerBase::TYPE_STD_MAP)); - $this->assertTrue($this->invoke('isStdContainerType', CompilerBase::TYPE_STD_ORDERED_MAP)); + $this->assertTrue($this->invoke('isStdContainerType', Type::STD_ARRAY)); + $this->assertTrue($this->invoke('isStdContainerType', Type::STD_VECTOR)); + $this->assertTrue($this->invoke('isStdContainerType', Type::STD_MAP)); + $this->assertTrue($this->invoke('isStdContainerType', Type::STD_ORDERED_MAP)); } public function testIsStdContainerTypeFalse(): void { - $this->assertFalse($this->invoke('isStdContainerType', CompilerBase::TYPE_ARRAY)); - $this->assertFalse($this->invoke('isStdContainerType', CompilerBase::TYPE_INT)); - $this->assertFalse($this->invoke('isStdContainerType', CompilerBase::TYPE_VAR)); - $this->assertFalse($this->invoke('isStdContainerType', CompilerBase::TYPE_OBJECT)); + $this->assertFalse($this->invoke('isStdContainerType', Type::ARRAY)); + $this->assertFalse($this->invoke('isStdContainerType', Type::INT)); + $this->assertFalse($this->invoke('isStdContainerType', Type::VAR)); + $this->assertFalse($this->invoke('isStdContainerType', Type::OBJECT)); } // ======================================================================== @@ -304,8 +305,8 @@ class TraitsTest extends TestCase public function testGetStdValueTypeBytes(): void { - $this->assertGreaterThan(0, $this->invoke('getStdValueTypeBytes', CompilerBase::TYPE_INT)); - $this->assertGreaterThan(0, $this->invoke('getStdValueTypeBytes', CompilerBase::TYPE_FLOAT)); - $this->assertGreaterThan(0, $this->invoke('getStdValueTypeBytes', CompilerBase::TYPE_BOOL)); + $this->assertGreaterThan(0, $this->invoke('getStdValueTypeBytes', Type::INT)); + $this->assertGreaterThan(0, $this->invoke('getStdValueTypeBytes', Type::FLOAT)); + $this->assertGreaterThan(0, $this->invoke('getStdValueTypeBytes', Type::BOOL)); } } diff --git a/src/CompilerBase.php b/src/CompilerBase.php index 04677ab2..9815dc0c 100644 --- a/src/CompilerBase.php +++ b/src/CompilerBase.php @@ -143,19 +143,6 @@ class CompilerBase implements PropertyAccessContext use LoopVarOptimizer; use SsaPropOptimizer; - public const string TYPE_VAR = 'php::Var'; - public const string TYPE_BOOL = 'php::Bool'; - public const string TYPE_INT = 'php::Int'; - public const string TYPE_FLOAT = 'php::Float'; - public const string TYPE_OBJECT = 'php::Object'; - public const string TYPE_ARRAY = 'php::Array'; - public const string TYPE_RESOURCE = 'php::Resource'; - public const string TYPE_STREAM = 'php::Stream'; - public const string TYPE_BIGINT = 'php::BigInt'; - public const string TYPE_DECIMAL = 'php::Decimal'; - public const string TYPE_BIGFLOAT = 'php::BigFloat'; - public const string TYPE_BOX = 'php::Box'; - protected const string NATIVE_PROPERTY_VALUE_VAR = 'var'; protected const string NATIVE_PROPERTY_VALUE_DYNAMIC = 'dynamic'; protected const int COMPOSITE_TYPE_MISMATCH = -1; @@ -169,18 +156,18 @@ class CompilerBase implements PropertyAccessContext * Use findKeywordMethod() for unified lookup including keyword extension methods. */ public const array KEYWORD_METHOD_MAP = [ - 'toInt' => self::TYPE_INT, - 'toFloat' => self::TYPE_FLOAT, - 'toString' => self::TYPE_STR, - 'toBool' => self::TYPE_BOOL, - 'toArray' => self::TYPE_ARRAY, - 'toStream' => self::TYPE_STREAM, - 'toBigInt' => self::TYPE_BIGINT, - 'toBigFloat' => self::TYPE_BIGFLOAT, - 'toDecimal' => self::TYPE_DECIMAL, - 'toObject' => self::TYPE_OBJECT, - 'toAny' => self::TYPE_VAR, - 'toRef' => self::TYPE_REF, + 'toInt' => Type::INT, + 'toFloat' => Type::FLOAT, + 'toString' => Type::STR, + 'toBool' => Type::BOOL, + 'toArray' => Type::ARRAY, + 'toStream' => Type::STREAM, + 'toBigInt' => Type::BIGINT, + 'toBigFloat' => Type::BIGFLOAT, + 'toDecimal' => Type::DECIMAL, + 'toObject' => Type::OBJECT, + 'toAny' => Type::VAR, + 'toRef' => Type::REF, ]; private const array STREAM_FUNCTIONS = [ @@ -191,15 +178,6 @@ class CompilerBase implements PropertyAccessContext 'stream_socket_accept', 'popen', ]; - public const string TYPE_STD_ARRAY = 'php::StdArray'; - public const string TYPE_STD_VECTOR = 'php::StdVector'; - public const string TYPE_STD_MAP = 'php::StdMap'; - public const string TYPE_STD_ORDERED_MAP = 'php::StdOrderedMap'; - public const string TYPE_ARGS = 'php::Args'; - public const string TYPE_STR = 'php::Str'; - public const string TYPE_REF = 'php::Ref'; - public const string TYPE_VOID = 'void'; - public const int DECL_TYPE_OF_RETURN = 1; public const int DECL_TYPE_OF_PROPERTY = 2; public const int DECL_TYPE_OF_CONST = 3; @@ -267,30 +245,30 @@ class CompilerBase implements PropertyAccessContext protected int $propIndex = 0; protected array $propMap = []; protected array $zendTypeMap = [ - 'int' => self::TYPE_INT, - 'float' => self::TYPE_FLOAT, - 'double' => self::TYPE_FLOAT, - 'bool' => self::TYPE_BOOL, - 'false' => self::TYPE_BOOL, - 'true' => self::TYPE_BOOL, - 'void' => self::TYPE_VOID, - 'never' => self::TYPE_VOID, - 'string' => self::TYPE_STR, - 'array' => self::TYPE_ARRAY, - 'object' => self::TYPE_OBJECT, - 'mixed' => self::TYPE_VAR, - 'null' => self::TYPE_VAR, - 'any' => self::TYPE_VAR, + 'int' => Type::INT, + 'float' => Type::FLOAT, + 'double' => Type::FLOAT, + 'bool' => Type::BOOL, + 'false' => Type::BOOL, + 'true' => Type::BOOL, + 'void' => Type::VOID, + 'never' => Type::VOID, + 'string' => Type::STR, + 'array' => Type::ARRAY, + 'object' => Type::OBJECT, + 'mixed' => Type::VAR, + 'null' => Type::VAR, + 'any' => Type::VAR, // callable 类型,可以是字符串、数组、对象 // 1) 'foo' 函数名称字符串, 2) [ $obj, 'bar' ] 对象方法数组, 3) Closure 对象, 4) [ 'class', 'staticMethod'] 类名+静态方法数组 - 'callable' => self::TYPE_VAR, + 'callable' => Type::VAR, // iterable 类型,可以是数组或者对象 - 'iterable' => self::TYPE_VAR, - 'stream' => self::TYPE_STREAM, - 'bigint' => self::TYPE_BIGINT, - 'bigfloat' => self::TYPE_BIGFLOAT, - 'decimal' => self::TYPE_DECIMAL, - 'box' => self::TYPE_BOX, + 'iterable' => Type::VAR, + 'stream' => Type::STREAM, + 'bigint' => Type::BIGINT, + 'bigfloat' => Type::BIGFLOAT, + 'decimal' => Type::DECIMAL, + 'box' => Type::BOX, ]; protected array $globalHeaders = [ 'phpx.h', @@ -408,15 +386,15 @@ class CompilerBase implements PropertyAccessContext private ?DiagnosticReporter $diagnosticReporter = null; protected FunctionContext $context; protected array $superGlobalVars = [ - '_GET' => self::TYPE_ARRAY, - '_POST' => self::TYPE_ARRAY, - '_COOKIE' => self::TYPE_ARRAY, - '_SERVER' => self::TYPE_ARRAY, - '_FILES' => self::TYPE_ARRAY, - '_SESSION' => self::TYPE_ARRAY, - '_REQUEST' => self::TYPE_ARRAY, - '_ENV' => self::TYPE_ARRAY, - 'GLOBALS' => self::TYPE_ARRAY, + '_GET' => Type::ARRAY, + '_POST' => Type::ARRAY, + '_COOKIE' => Type::ARRAY, + '_SERVER' => Type::ARRAY, + '_FILES' => Type::ARRAY, + '_SESSION' => Type::ARRAY, + '_REQUEST' => Type::ARRAY, + '_ENV' => Type::ARRAY, + 'GLOBALS' => Type::ARRAY, ]; protected array $globalVars = []; protected bool $nativeTypes = false; @@ -649,7 +627,7 @@ class CompilerBase implements PropertyAccessContext public function getTypeFromZendType(string $type): string { - return $this->zendTypeMap[$type] ?? self::TYPE_VAR; + return $this->zendTypeMap[$type] ?? Type::VAR; } public function getObjectType(string $object): string @@ -976,7 +954,7 @@ class CompilerBase implements PropertyAccessContext return $this->context->globalVars[$name]; } - return self::TYPE_VAR; + return Type::VAR; } /** @@ -1097,7 +1075,7 @@ class CompilerBase implements PropertyAccessContext protected function isVoidValueExpr(NodeAbstract $expr): bool { - return $this->detectTypeOfExpr($expr) === self::TYPE_VOID; + return $this->detectTypeOfExpr($expr) === Type::VOID; } protected function wrapVoidExprAsNull(NodeAbstract $expr, string $exprCode): string @@ -1210,7 +1188,7 @@ class CompilerBase implements PropertyAccessContext if (isset($this->context->ceWrappers[$className])) { return $this->context->ceWrappers[$className]; } - $object = $this->addTmpVar(self::TYPE_OBJECT); + $object = $this->addTmpVar(Type::OBJECT); $this->context->beforeStmtLines[] = 'Z_PTR_P(' . $object . '.ptr()) = ' . $this->getClassEntryPtr($className) . ';'; $this->context->ceWrappers[$className] = $object; return $object; @@ -1259,7 +1237,7 @@ class CompilerBase implements PropertyAccessContext */ protected function getInlineString(string $string): string { - return self::TYPE_STR . '{ZEND_STRL(' . $this->genCharPtr($string, true) . ')}'; + return Type::STR . '{ZEND_STRL(' . $this->genCharPtr($string, true) . ')}'; } protected function parseScalar(Node\Scalar $expr): string @@ -1518,7 +1496,7 @@ class CompilerBase implements PropertyAccessContext $code = ''; $this->appendCapturedStmtLines($code, $beforeStmts); if ($afterStmts) { - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $code .= $this->getIndent() . $tmpVar . ' = ' . $condExpr . ';' . PHP_EOL; $this->appendCapturedStmtLines($code, $afterStmts); $condExpr = $tmpVar; @@ -1874,7 +1852,7 @@ class CompilerBase implements PropertyAccessContext { if ($this->functionDef->returnsByRef) { if ($v->expr === null) { - return 'return ' . self::TYPE_REF . '{};'; + return 'return ' . Type::REF . '{};'; } if (!$this->isVarExpr($v->expr) && !$this->isPropertyFetch($v->expr) @@ -1887,7 +1865,7 @@ class CompilerBase implements PropertyAccessContext if (!$this->hasVar($name)) { $this->errorUndefinedVariable($v->expr); } - if ($this->hasLocalVar($name) && $this->getVarType($name) !== self::TYPE_VAR && $this->getVarType($name) !== self::TYPE_REF) { + if ($this->hasLocalVar($name) && $this->getVarType($name) !== Type::VAR && $this->getVarType($name) !== Type::REF) { $isParameter = false; foreach ($this->functionDef->argInfoList as $argInfo) { if ($argInfo->name === $name) { @@ -1900,7 +1878,7 @@ class CompilerBase implements PropertyAccessContext } // The declaration is emitted after parsing the body, so a local can // be promoted to Variant before C++ is generated. - $this->context->localVars[$name] = self::TYPE_VAR; + $this->context->localVars[$name] = Type::VAR; } return 'return ' . $name . '.toReference();'; } @@ -1928,7 +1906,7 @@ class CompilerBase implements PropertyAccessContext 'return value' ); } - if ($this->functionDef->returnType === self::TYPE_VOID and !$this->context->inClosure) { + if ($this->functionDef->returnType === Type::VOID and !$this->context->inClosure) { return 'return;'; } elseif ($this->shouldCheckClosureReturnType()) { return $this->genClosureCheckedReturn(self::VALUE_NULL); @@ -1965,11 +1943,11 @@ class CompilerBase implements PropertyAccessContext // 匿名函数的返回值一定是 var if (!$this->context->inClosure) { - if ($returnType === 'void') { + if ($returnType === Type::VOID) { $this->fatalError($v, 'The return type is void, cannot return any value'); } } else { - $returnType = self::TYPE_VAR; + $returnType = Type::VAR; } $returnObjectCheckClass = ''; @@ -2053,7 +2031,7 @@ class CompilerBase implements PropertyAccessContext protected function genCheckedReturnAssignment(string $exprCode, bool $closure): array { $tmpVar = $this->genTmpVarName(); - $this->addLocalVar($tmpVar, self::TYPE_VAR); + $this->addLocalVar($tmpVar, Type::VAR); $code = $tmpVar . ' = ' . $exprCode . ';' . PHP_EOL; $code .= $closure ? $this->genClosureReturnCheck($tmpVar) : $this->genUnionReturnCheck($tmpVar); @@ -2244,7 +2222,7 @@ class CompilerBase implements PropertyAccessContext continue; } $interfaceConstDef = $interfaceDef->constants[$const]; - if ($interfaceConstDef->type === self::TYPE_ARRAY) { + if ($interfaceConstDef->type === Type::ARRAY) { return self::PREFIX . $this->getNativeName($interfaceConstDef->name, $interfaceDef->namespace, $interfaceDef->name); } $expr->setAttribute('nativeConst', $interfaceConstDef); @@ -2257,7 +2235,7 @@ class CompilerBase implements PropertyAccessContext if ($classDef instanceof ClassDef && !$this->checkAccessible($classDef, $constDef->flags)) { $this->fatalError($expr, 'Constant `' . $classDef->getNamespacedName() . '::' . $const . '` is not accessible'); } - if ($constDef->type === self::TYPE_ARRAY) { + if ($constDef->type === Type::ARRAY) { return self::PREFIX . $this->getNativeName($constDef->name, $classDef->namespace, $classDef->name); } else { $expr->setAttribute('nativeConst', $constDef); @@ -2321,7 +2299,7 @@ class CompilerBase implements PropertyAccessContext } $name = $this->parseIdentifier($var); if ($this->isStdContainer($name)) { - return self::TYPE_ARRAY; + return Type::ARRAY; } return $this->getVarType($name); } @@ -2334,29 +2312,29 @@ class CompilerBase implements PropertyAccessContext return $this->detectTypeOfExpr($expr->expr); case 'Expr_BitwiseNot': $inner = $this->detectTypeOfExpr($expr->expr); - return $inner === self::TYPE_BIGINT ? self::TYPE_BIGINT : self::TYPE_INT; + return $inner === Type::BIGINT ? Type::BIGINT : Type::INT; case 'Expr_Print': case 'Expr_Cast_Int': - return self::TYPE_INT; + return Type::INT; case 'Scalar_Int': - return $this->bigintTypes ? self::TYPE_BIGINT : self::TYPE_INT; + return $this->bigintTypes ? Type::BIGINT : Type::INT; case 'Expr_Cast_Float': case 'Expr_Cast_Double': - return self::TYPE_FLOAT; + return Type::FLOAT; case 'Scalar_Float': if ($this->isBigIntLiteral($expr)) { - return self::TYPE_BIGINT; + return Type::BIGINT; } if ($this->isDecimalLiteral($expr) || $this->decimalTypes) { - return self::TYPE_DECIMAL; + return Type::DECIMAL; } - return self::TYPE_FLOAT; + return Type::FLOAT; case 'Expr_Cast_Bool': case 'Scalar_Bool': - return self::TYPE_BOOL; + return Type::BOOL; case 'Expr_Array': case 'Expr_Cast_Array': - return self::TYPE_ARRAY; + return Type::ARRAY; case 'Expr_BinaryOp_Plus': case 'Expr_BinaryOp_Minus': case 'Expr_BinaryOp_Mul': @@ -2371,24 +2349,24 @@ class CompilerBase implements PropertyAccessContext case 'Expr_BinaryOp_BooleanAnd': $leftType = $this->detectTypeOfExpr($expr->left); $rightType = $this->detectTypeOfExpr($expr->right); - if ($leftType === self::TYPE_BIGFLOAT || $rightType === self::TYPE_BIGFLOAT) { - return self::TYPE_BIGFLOAT; + if ($leftType === Type::BIGFLOAT || $rightType === Type::BIGFLOAT) { + return Type::BIGFLOAT; } - if ($leftType === self::TYPE_DECIMAL || $rightType === self::TYPE_DECIMAL) { - return self::TYPE_DECIMAL; + if ($leftType === Type::DECIMAL || $rightType === Type::DECIMAL) { + return Type::DECIMAL; } - if ($leftType === self::TYPE_BIGINT || $rightType === self::TYPE_BIGINT) { + if ($leftType === Type::BIGINT || $rightType === Type::BIGINT) { if ($exprType === 'Expr_BinaryOp_Div') { // BigInt division produces BigInt (integer division); BigDecimal in future - return self::TYPE_BIGINT; + return Type::BIGINT; } - return self::TYPE_BIGINT; + return Type::BIGINT; } - if ($leftType === self::TYPE_FLOAT || $rightType === self::TYPE_FLOAT) { - return self::TYPE_FLOAT; + if ($leftType === Type::FLOAT || $rightType === Type::FLOAT) { + return Type::FLOAT; } - if ($leftType === self::TYPE_INT || $rightType === self::TYPE_INT) { - return self::TYPE_INT; + if ($leftType === Type::INT || $rightType === Type::INT) { + return Type::INT; } break; case 'Expr_FuncCall': @@ -2398,29 +2376,29 @@ class CompilerBase implements PropertyAccessContext if (in_array($name, ['abs', 'pow', 'sqrt', 'floor', 'ceil', 'round'], true) && !empty($expr->args)) { $argType = $this->detectTypeOfExpr($expr->args[0]->value); if ( - $argType === self::TYPE_BIGINT + $argType === Type::BIGINT && in_array($name, ['abs', 'pow', 'sqrt'], true) ) { - return self::TYPE_BIGINT; + return Type::BIGINT; } if ( - $argType === self::TYPE_DECIMAL + $argType === Type::DECIMAL && in_array($name, ['abs', 'pow', 'sqrt', 'floor', 'ceil', 'round'], true) ) { - return self::TYPE_DECIMAL; + return Type::DECIMAL; } if ( - $argType === self::TYPE_BIGFLOAT + $argType === Type::BIGFLOAT && in_array($name, ['abs', 'sqrt'], true) ) { - return self::TYPE_BIGFLOAT; + return Type::BIGFLOAT; } } if (in_array($name, self::STREAM_FUNCTIONS)) { - return self::TYPE_STREAM; + return Type::STREAM; } if (count($expr->args) === 1 and $this->isPlaceholderExpr($expr->args[0])) { - return self::TYPE_OBJECT; + return Type::OBJECT; } if ($this->hasFunction($name)) { return $this->getFunction($name)->returnType; @@ -2440,7 +2418,7 @@ class CompilerBase implements PropertyAccessContext $classDef = $this->resolveObjectClassDef($expr->var); if ($classDef !== null && $classDef->hasMethod($method)) { if (count($expr->args) === 1 and $this->isPlaceholderExpr($expr->args[0])) { - return self::TYPE_OBJECT; + return Type::OBJECT; } return $classDef->getMethod($method)->getReturnType(); } @@ -2462,7 +2440,7 @@ class CompilerBase implements PropertyAccessContext } else { $type = $this->detectTypeOfExpr($expr->var); } - if ($type !== self::TYPE_VAR && !$this->checkArgType($type, self::TYPE_OBJECT)) { + if ($type !== Type::VAR && !$this->checkArgType($type, Type::OBJECT)) { $retType = $this->detectUniversalMethodReturnType($type, $method); if ($retType !== null) { return $retType; @@ -2474,19 +2452,19 @@ class CompilerBase implements PropertyAccessContext if ($this->isNameExpr($expr->class) && $this->isIdExpr($expr->name)) { // First-class callable syntax creates a Closure, not a method return value if (count($expr->args) === 1 and $this->isPlaceholderExpr($expr->args[0])) { - return self::TYPE_OBJECT; + return Type::OBJECT; } $className = $this->parseIdentifier($expr->class); if (strtolower($className) === 'std') { $method = strtolower($this->parseIdentifier($expr->name)); return match ($method) { - 'int' => self::TYPE_INT, - 'float' => self::TYPE_FLOAT, - 'bool' => self::TYPE_BOOL, - 'bigint' => self::TYPE_BIGINT, - 'decimal' => self::TYPE_DECIMAL, - 'bigfloat' => self::TYPE_BIGFLOAT, - default => self::TYPE_VAR, + 'int' => Type::INT, + 'float' => Type::FLOAT, + 'bool' => Type::BOOL, + 'bigint' => Type::BIGINT, + 'decimal' => Type::DECIMAL, + 'bigfloat' => Type::BIGFLOAT, + default => Type::VAR, }; } if ($className === 'self') { @@ -2552,7 +2530,7 @@ class CompilerBase implements PropertyAccessContext if ($attr['accessLevel'] === $attr['totalLevel']) { return $this->context->stdArrays[$attr['var']]['type']; } else { - return self::TYPE_ARRAY; + return Type::ARRAY; } } if ($this->isStdContainerExpr($expr)) { @@ -2564,7 +2542,7 @@ class CompilerBase implements PropertyAccessContext } break; case 'Expr_New': - return self::TYPE_OBJECT; + return Type::OBJECT; case 'Expr_Assign': case 'Expr_AssignOp_BitwiseAnd': case 'Expr_AssignOp_BitwiseOr': @@ -2575,12 +2553,12 @@ class CompilerBase implements PropertyAccessContext case 'Expr_ConstFetch': return $this->detectConstType($expr); case 'Scalar_String': - return self::TYPE_STR; + return Type::STR; default: break; } - return self::TYPE_VAR; + return Type::VAR; } protected function genDynamicPropIncDec($var, string $op, bool $isPre): ?string @@ -2597,14 +2575,14 @@ class CompilerBase implements PropertyAccessContext } if ($getter !== null && $setter !== null) { $tmpVar = $this->genTmpVarName(); - $this->addLocalVar($tmpVar, self::TYPE_VAR); + $this->addLocalVar($tmpVar, Type::VAR); $read = $this->emitPropertyHookGetterCall($var, $getter); if ($isPre) { $set = $this->emitPropertyHookSetterCall($var, $setter, new Expr\Variable($tmpVar)); $this->context->beforeStmtLines[] = "{$tmpVar} = {$read} {$op} 1; {$set};"; } else { $nextVar = $this->genTmpVarName(); - $this->addLocalVar($nextVar, self::TYPE_VAR); + $this->addLocalVar($nextVar, Type::VAR); $set = $this->emitPropertyHookSetterCall($var, $setter, new Expr\Variable($nextVar)); $this->context->beforeStmtLines[] = "{$tmpVar} = {$read};"; $this->context->afterStmtLines[] = "{$nextVar} = {$tmpVar} {$op} 1; {$set};"; @@ -2616,7 +2594,7 @@ class CompilerBase implements PropertyAccessContext } $tmpVar = $this->genTmpVarName(); - $this->addLocalVar($tmpVar, self::TYPE_VAR); + $this->addLocalVar($tmpVar, Type::VAR); if ($isPre) { $this->context->beforeStmtLines[] = "{$tmpVar} = " . $this->emitDynamicPropertyFetchRead($var, $target) . " {$op} 1; " . $this->emitDynamicPropertyFetchWrite($var, $tmpVar, $target) . ';'; } else { @@ -2636,7 +2614,7 @@ class CompilerBase implements PropertyAccessContext } $type = $this->detectVarType($expr->var); - if ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) { + if ($type === Type::BIGINT || $type === Type::DECIMAL || $type === Type::BIGFLOAT) { $this->fatalError($expr, 'Cannot use ++ on ' . $type . '. Use += 1 instead (Big* types are immutable).'); } $result = '++' . $this->parseWritableIdentifier($expr->var); @@ -2884,7 +2862,7 @@ class CompilerBase implements PropertyAccessContext $this->errorUndefinedVariable($expr->var); } $type = $this->detectVarType($expr->var); - if ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) { + if ($type === Type::BIGINT || $type === Type::DECIMAL || $type === Type::BIGFLOAT) { $opName = $op === '+' ? '++' : '--'; $this->fatalError($expr, "Cannot use {$opName} on {$type}. Use " . ($op === '+' ? '+= 1' : '-= 1') . ' instead (Big* types are immutable).'); } @@ -2899,7 +2877,7 @@ class CompilerBase implements PropertyAccessContext $class = $this->identifierToStr($expr->var->class); $prop = $this->identifierToStr($expr->var->name); $tmpVar = $this->genTmpVarName(); - $this->addLocalVar($tmpVar, self::TYPE_VAR); + $this->addLocalVar($tmpVar, Type::VAR); $this->context->beforeStmtLines[] = $tmpVar . ' = ' . Symbol::getStaticProperty() . '(' . $class . ', ' . $prop . ');'; $this->context->afterStmtLines[] = Symbol::setStaticProperty() . '(' . $class . ', ' . $prop . ', ' . $tmpVar . ' ' . $op . ' 1);'; @@ -2927,7 +2905,7 @@ class CompilerBase implements PropertyAccessContext } $type = $this->detectVarType($expr->var); - if ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) { + if ($type === Type::BIGINT || $type === Type::DECIMAL || $type === Type::BIGFLOAT) { $this->fatalError($expr, 'Cannot use -- on ' . $type . '. Use -= 1 instead (Big* types are immutable).'); } $result = '--' . $this->parseWritableIdentifier($expr->var); @@ -3054,7 +3032,7 @@ class CompilerBase implements PropertyAccessContext return 'php::instanceOf(' . $value . ', ' . $classPtr . ')'; } else { [$value, $beforeStmts, $afterStmts] = $this->parseExprWithCapturedStmts($expr->expr); - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $this->appendCapturedStmtLinesToContext($beforeStmts); $this->context->beforeStmtLines[] = $tmpVar . ' = ' . $value . ';'; $this->appendCapturedStmtLinesToContext($afterStmts); @@ -3107,10 +3085,10 @@ class CompilerBase implements PropertyAccessContext foreach ($expr->vars as $v) { $name = $this->parseVariable($v); if (!$this->hasGlobalVar($name)) { - $this->addGlobalVar($name, self::TYPE_VAR); + $this->addGlobalVar($name, Type::VAR); } if (!$this->hasScopeGlobalVar($name)) { - $this->addScopeGlobalVar($name, self::TYPE_VAR); + $this->addScopeGlobalVar($name, Type::VAR); } } return ''; @@ -3143,13 +3121,13 @@ class CompilerBase implements PropertyAccessContext $list = []; foreach ($v->vars as $var) { $varName = $this->escapeVarName($var->var->name); - $type = $var->default ? $this->detectTypeOfExpr($var->default) : self::TYPE_VAR; + $type = $var->default ? $this->detectTypeOfExpr($var->default) : Type::VAR; if ($var->default) { $this->assertExprCanBeUsedAsValue($var->default, 'static variable default value'); } $globalVar = $this->addStaticVar($var->var, $varName, $type); - $list[] = self::TYPE_VAR . ' &' . $varName . ' = ' . $this->escapeGlobalVar($globalVar) . ';'; + $list[] = Type::VAR . ' &' . $varName . ' = ' . $this->escapeGlobalVar($globalVar) . ';'; if ($var->default) { $initState = self::STATIC_VAR . $varName . '_initialized'; $initCode = $this->getIndent() . 'static bool ' . $initState . ' = false;'; @@ -3324,16 +3302,16 @@ class CompilerBase implements PropertyAccessContext $this->fatalError($expr, 'Cannot use [] for reading'); } $dim = $this->parseIdentifier($expr->dim); - $list[] = '{php::ArrayDimFetch, ' . self::TYPE_VAR . '(' . $dim . ')}'; + $list[] = '{php::ArrayDimFetch, ' . Type::VAR . '(' . $dim . ')}'; } elseif ($this->isPropertyFetch($expr)) { $name = $this->identifierToStr($expr->name, literal: true); - $list[] = '{php::PropertyFetch, ' . self::TYPE_VAR . '(' . $name . ')}'; + $list[] = '{php::PropertyFetch, ' . Type::VAR . '(' . $name . ')}'; } elseif ($this->isVarExpr($expr)) { $var = $this->parseIdentifier($expr); break; } else { $var = $this->genTmpVarName(); - $this->addLocalVar($var, self::TYPE_VAR); + $this->addLocalVar($var, Type::VAR); $this->context->beforeStmtLines[] = $var . '=' . $this->parseExpr($expr) . ';'; break; } @@ -3343,7 +3321,7 @@ class CompilerBase implements PropertyAccessContext $list = array_reverse($list); if ($getValue) { - $result = $this->addTmpVar(self::TYPE_VAR); + $result = $this->addTmpVar(Type::VAR); $node->setAttribute('chainOpResult', $result); return $fn . '(' . $var . ', {' . implode(', ', $list) . '}, ' . $result . ')'; } else { @@ -3390,7 +3368,7 @@ class CompilerBase implements PropertyAccessContext return $this->getTypeFromZendType($returnType); } - return self::TYPE_VAR; + return Type::VAR; } protected function detectMethodCallReturnType(string $class, string $method): string @@ -3399,7 +3377,7 @@ class CompilerBase implements PropertyAccessContext if ($returnType) { return $this->getTypeFromZendType($returnType); } - return self::TYPE_VAR; + return Type::VAR; } protected function genObjvalCall(Expr\FuncCall $expr): string @@ -3612,7 +3590,7 @@ class CompilerBase implements PropertyAccessContext return $code; } - protected function checkVar(NodeAbstract $node, string $name, string $defaultType = self::TYPE_VAR): void + protected function checkVar(NodeAbstract $node, string $name, string $defaultType = Type::VAR): void { if (!$this->hasVar($name)) { $this->addLocalVar($name, $defaultType); @@ -3632,11 +3610,11 @@ class CompilerBase implements PropertyAccessContext protected function checkVarAssignExpr(NodeAbstract $left, string $toType, string $fromType): bool { - if ($toType === self::TYPE_VAR or $fromType === self::TYPE_VAR) { + if ($toType === Type::VAR or $fromType === Type::VAR) { return true; } // 引用当前没有类型信息,按照 var 处理 - if ($toType === self::TYPE_REF or $fromType === self::TYPE_REF) { + if ($toType === Type::REF or $fromType === Type::REF) { return true; } // 类型一致,可以互相赋值 @@ -3648,7 +3626,7 @@ class CompilerBase implements PropertyAccessContext return true; } // BigInt/BigFloat/Decimal 与原生类型之间可能发生隐式转换,允许重新赋值 - $bigTypes = [self::TYPE_BIGINT, self::TYPE_DECIMAL, self::TYPE_BIGFLOAT]; + $bigTypes = [Type::BIGINT, Type::DECIMAL, Type::BIGFLOAT]; if (in_array($toType, $bigTypes, true) or in_array($fromType, $bigTypes, true)) { return true; } @@ -3727,7 +3705,7 @@ class CompilerBase implements PropertyAccessContext continue; } $code .= $this->getIndent(); - if ($type === self::TYPE_STD_ARRAY) { + if ($type === Type::STD_ARRAY) { $info = $this->context->stdArrays[$name]; if (isset($info['boxExpr'])) { $code .= 'auto &' . $name . '_ref = php::toStdContainer<' . $info['decl'] . '>(' . $info['boxExpr'] . ', ' . $info['typeId'] . ');'; @@ -3736,7 +3714,7 @@ class CompilerBase implements PropertyAccessContext $code .= 'php::Var ' . $name . ' = php::Var(new ' . $containerType . '(' . $info['typeId'] . '));' . PHP_EOL; $code .= $this->getIndent() . 'auto &' . $name . '_ref = ' . $name . '.toBox<' . $containerType . '>()->container;'; } - } elseif ($type === self::TYPE_STD_VECTOR) { + } elseif ($type === Type::STD_VECTOR) { $info = $this->context->stdContainers[$name]; if (isset($info['boxExpr'])) { $code .= 'auto &' . $name . '_ref = php::toStdContainer<' . $info['decl'] . '>(' . $info['boxExpr'] . ', ' . $info['typeId'] . ');'; @@ -3750,7 +3728,7 @@ class CompilerBase implements PropertyAccessContext $code .= 'php::Var ' . $name . ' = php::Var(' . $boxCtor . ');' . PHP_EOL; $code .= $this->getIndent() . 'auto &' . $name . '_ref = ' . $name . '.toBox<' . $containerType . '>()->container;'; } - } elseif ($type === self::TYPE_STD_MAP || $type === self::TYPE_STD_ORDERED_MAP) { + } elseif ($type === Type::STD_MAP || $type === Type::STD_ORDERED_MAP) { $info = $this->context->stdContainers[$name]; if (isset($info['boxExpr'])) { $code .= 'auto &' . $name . '_ref = php::toStdContainer<' . $info['decl'] . '>(' . $info['boxExpr'] . ', ' . $info['typeId'] . ');'; @@ -3759,11 +3737,11 @@ class CompilerBase implements PropertyAccessContext $code .= 'php::Var ' . $name . ' = php::Var(new ' . $containerType . '(' . $info['typeId'] . '));' . PHP_EOL; $code .= $this->getIndent() . 'auto &' . $name . '_ref = ' . $name . '.toBox<' . $containerType . '>()->container;'; } - } elseif ($type === self::TYPE_STREAM || $type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) { - $code .= self::TYPE_VAR . ' ' . $name . ';'; + } elseif ($type === Type::STREAM || $type === Type::BIGINT || $type === Type::DECIMAL || $type === Type::BIGFLOAT) { + $code .= Type::VAR . ' ' . $name . ';'; } else { $code .= $type . ' ' . $name; - if ($type === self::TYPE_INT or $type === self::TYPE_FLOAT or $type === self::TYPE_BOOL) { + if ($type === Type::INT or $type === Type::FLOAT or $type === Type::BOOL) { $code .= ' = 0'; } $code .= ';'; @@ -3788,20 +3766,20 @@ class CompilerBase implements PropertyAccessContext if ($name === 'GLOBALS') { continue; } - $code .= $this->getIndent() . self::TYPE_VAR . ' &' . $name . ' = ' . $this->escapeGlobalVar($name) . ';' . PHP_EOL; + $code .= $this->getIndent() . Type::VAR . ' &' . $name . ' = ' . $this->escapeGlobalVar($name) . ';' . PHP_EOL; } foreach ($this->context->objectProps as $name => $info) { if (($info['kind'] ?? 'zval') === 'var') { - $code .= $this->getIndent() . self::TYPE_VAR . ' ' . $name . ' = ' . $info['getter'] . ';' . PHP_EOL; + $code .= $this->getIndent() . Type::VAR . ' ' . $name . ' = ' . $info['getter'] . ';' . PHP_EOL; } else { - $zvalMacro = ($info['type'] === self::TYPE_FLOAT) ? 'Z_DVAL_P' : 'Z_LVAL_P'; + $zvalMacro = ($info['type'] === Type::FLOAT) ? 'Z_DVAL_P' : 'Z_LVAL_P'; $code .= $this->getIndent() . $info['type'] . ' &' . $name . ' = ' . $zvalMacro . '(' . $info['getter'] . '.unwrap_ptr());' . PHP_EOL; } } foreach ($this->context->staticPropRefs as $name => $info) { $getter = Symbol::getStaticProperty() . '(' . $info['classPtr'] . ', ' . $info['offsetExpr'] . ')'; if (($info['kind'] ?? 'zval') === 'var') { - $code .= $this->getIndent() . self::TYPE_VAR . ' ' . $name . ' = ' . $getter . ';' . PHP_EOL; + $code .= $this->getIndent() . Type::VAR . ' ' . $name . ' = ' . $getter . ';' . PHP_EOL; } else { $code .= $this->getIndent() . 'zval *' . $name . ' = ' . $getter . '.unwrap_ptr();' . PHP_EOL; } @@ -3812,20 +3790,20 @@ class CompilerBase implements PropertyAccessContext protected function genReturnCode(): string { if ($this->functionDef->returnsByRef) { - return $this->getIndent() . 'return ' . self::TYPE_REF . '{};'; + return $this->getIndent() . 'return ' . Type::REF . '{};'; } if ($this->shouldCheckClosureReturnType()) { return $this->genClosureCheckedReturn(self::VALUE_NULL); } - if ($this->functionDef->returnType === self::TYPE_VOID) { + if ($this->functionDef->returnType === Type::VOID) { return ''; } if ($this->functionDef->returnTypeCheck && !$this->context->inClosure) { return $this->genUnionCheckedReturn(self::VALUE_NULL); } - if ($this->functionDef->returnType === self::TYPE_INT - or $this->functionDef->returnType === self::TYPE_FLOAT - or $this->functionDef->returnType === self::TYPE_BOOL) { + if ($this->functionDef->returnType === Type::INT + or $this->functionDef->returnType === Type::FLOAT + or $this->functionDef->returnType === Type::BOOL) { return $this->getIndent() . 'return 0;'; } else { return $this->getIndent() . 'return ' . self::VALUE_NULL . ';'; diff --git a/src/Generator/AnonClassGenerator.php b/src/Generator/AnonClassGenerator.php index f92f2dd4..211125d4 100644 --- a/src/Generator/AnonClassGenerator.php +++ b/src/Generator/AnonClassGenerator.php @@ -8,6 +8,8 @@ namespace TypePhp\Generator; +use TypePhp\Type; + use PhpParser\Node; use PhpParser\NodeAbstract; use PhpParser\Node\Identifier; @@ -175,7 +177,7 @@ trait AnonClassGenerator if ($classDef->hasMethod($methodName)) { $functionDef = $classDef->getMethod($methodName)->functionDef; return $functionDef !== null - && ($functionDef->returnTypeUndeclared || $functionDef->returnType === self::TYPE_VAR); + && ($functionDef->returnTypeUndeclared || $functionDef->returnType === Type::VAR); } $className = $classDef->extends; continue; diff --git a/src/Generator/CallArgumentGenerator.php b/src/Generator/CallArgumentGenerator.php index a50a63ca..0347667e 100644 --- a/src/Generator/CallArgumentGenerator.php +++ b/src/Generator/CallArgumentGenerator.php @@ -7,6 +7,8 @@ namespace TypePhp\Generator; +use TypePhp\Type; + use PhpParser\Modifiers; use PhpParser\Node; use PhpParser\Node\ArrayItem; @@ -110,14 +112,14 @@ trait CallArgumentGenerator $arg = $variadicArgs[0][1]; if ($this->isVarExpr($arg->value)) { $var = $this->parseIdentifier($arg->value); - if ($this->getVarType($var) === self::TYPE_ARRAY) { + if ($this->getVarType($var) === Type::ARRAY) { return $var; } } return $this->convertArrayExpr($this->parseExpr($arg->value)); } - $tmpVar = $this->addTmpVar(self::TYPE_ARRAY); + $tmpVar = $this->addTmpVar(Type::ARRAY); foreach ($variadicArgs as [$name, $arg]) { if ($arg->unpack) { $this->context->beforeStmtLines[] = $tmpVar . '.merge(' . $this->parseArrayArg($arg) . ');'; @@ -151,7 +153,7 @@ trait CallArgumentGenerator $tmpVar = $this->genTmpVarName(); - $array = self::TYPE_ARRAY . ' ' . $tmpVar . ';'; + $array = Type::ARRAY . ' ' . $tmpVar . ';'; foreach ($namedArgs as $k => $v) { $array .= $tmpVar . '.set(' . $this->getLiteralString($k) . ', ' . $v . ');' . PHP_EOL; } @@ -439,7 +441,7 @@ trait CallArgumentGenerator $globalVar = $this->parseGlobalsArrayDimFetch($arg->value); // 全局变量作为引用参数 if ($byRef) { - $ref = $this->addTmpVar(self::TYPE_REF); + $ref = $this->addTmpVar(Type::REF); $this->context->beforeStmtLines[] = $ref . ' = ' . $globalVar . '.toReference();'; $this->addPositionalCallArg('&' . $ref, $arrayArgsVar, $list_args); } else { @@ -477,7 +479,7 @@ trait CallArgumentGenerator $this->fatalError($arg, 'The constants cannot be used as an argument for a reference-type parameter'); } $tmpRef = $this->genTmpVarName(); - $this->addLocalVar($tmpRef, self::TYPE_REF); + $this->addLocalVar($tmpRef, Type::REF); $this->context->beforeStmtLines[] = $tmpRef . ' = ' . $this->parseChainedExpr($arg->value, self::OP_REFVAL) . ';'; $this->addPositionalCallArg('&' . $tmpRef, $arrayArgsVar, $list_args); continue; @@ -541,7 +543,7 @@ trait CallArgumentGenerator { if ($argsVar === null) { $argsVar = $this->genTmpVarName(); - $this->context->beforeStmtLines[] = self::TYPE_ARGS . ' ' . $argsVar . '{' . Symbol::argList() . '{' . implode(', ', $listArgs) . '}};'; + $this->context->beforeStmtLines[] = Type::ARGS . ' ' . $argsVar . '{' . Symbol::argList() . '{' . implode(', ', $listArgs) . '}};'; $listArgs = []; } return $argsVar; @@ -551,7 +553,7 @@ trait CallArgumentGenerator { if ($arrayArgsVar === null) { $arrayArgsVar = $this->genTmpVarName(); - $this->context->beforeStmtLines[] = self::TYPE_ARRAY . ' ' . $arrayArgsVar . '{' . implode(', ', $listArgs) . '};'; + $this->context->beforeStmtLines[] = Type::ARRAY . ' ' . $arrayArgsVar . '{' . implode(', ', $listArgs) . '};'; $listArgs = []; } return $arrayArgsVar; @@ -561,7 +563,7 @@ trait CallArgumentGenerator { if ($namedArgsVar === null) { $namedArgsVar = $this->genTmpVarName(); - $this->context->beforeStmtLines[] = self::TYPE_ARRAY . ' ' . $namedArgsVar . ';'; + $this->context->beforeStmtLines[] = Type::ARRAY . ' ' . $namedArgsVar . ';'; $this->context->afterStmtLines[] = $namedArgsVar . '.unset();'; } return $namedArgsVar; @@ -617,7 +619,7 @@ trait CallArgumentGenerator $array = $this->parseIdentifier($arg->value->var); if ($array === 'GLOBALS') { $globalVar = $this->parseGlobalsArrayDimFetch($arg->value); - $ref = $this->addTmpVar(self::TYPE_REF); + $ref = $this->addTmpVar(Type::REF); $this->context->beforeStmtLines[] = $ref . ' = ' . $globalVar . '.toReference();'; return '&' . $ref; } @@ -635,7 +637,7 @@ trait CallArgumentGenerator } $tmpRef = $this->genTmpVarName(); - $this->addLocalVar($tmpRef, self::TYPE_REF); + $this->addLocalVar($tmpRef, Type::REF); $this->context->beforeStmtLines[] = $tmpRef . ' = ' . $this->parseChainedExpr($arg->value, self::OP_REFVAL) . ';'; return '&' . $tmpRef; } @@ -684,7 +686,7 @@ trait CallArgumentGenerator $array = $this->parseIdentifier($inner->var); if ($array === 'GLOBALS') { $globalVar = $this->parseGlobalsArrayDimFetch($inner); - $ref = $this->addTmpVar(self::TYPE_REF); + $ref = $this->addTmpVar(Type::REF); $this->context->beforeStmtLines[] = $ref . ' = ' . $globalVar . '.toReference();'; return '&' . $ref; } @@ -706,15 +708,15 @@ trait CallArgumentGenerator { if (!$this->hasVar($name)) { // 若参数是引用类型,可以传入未定义变量,将立即创建变量作为引用 - $this->addLocalVar($name, self::TYPE_REF); + $this->addLocalVar($name, Type::REF); } else { // 本地变量,且是原生类型,则转为普通变量 if ($this->hasLocalVar($name) and $this->isNativeType($this->getVarType($name))) { - $this->context->localVars[$name] = self::TYPE_VAR; + $this->context->localVars[$name] = Type::VAR; } // 需要引用类型的参数,使用临时变量作为引用,并替换掉实际的参数 $tmpVar = $this->genTmpVarName(); - $this->addLocalVar($tmpVar, self::TYPE_REF); + $this->addLocalVar($tmpVar, Type::REF); $this->context->beforeStmtLines[] = $tmpVar . ' = ' . $this->parseExpr($arg->value) . '.toReference();'; $name = $tmpVar; } @@ -771,7 +773,7 @@ trait CallArgumentGenerator if (!$this->hasVar($var)) { $this->errorUndefinedVariable($value); } - if ($this->getVarType($var) === self::TYPE_ARRAY) { + if ($this->getVarType($var) === Type::ARRAY) { return $var; } } diff --git a/src/Generator/ClosureGenerator.php b/src/Generator/ClosureGenerator.php index 2222bf23..8a27fbd3 100644 --- a/src/Generator/ClosureGenerator.php +++ b/src/Generator/ClosureGenerator.php @@ -8,6 +8,8 @@ namespace TypePhp\Generator; +use TypePhp\Type; + use TypePhp\Entity\ArgInfo; use TypePhp\Context\FunctionContext; use PhpParser\Node; @@ -80,9 +82,9 @@ trait ClosureGenerator $code = $this->getIndent() . 'php::ClosureFn ' . $tmpVar . ' = [](' . 'INTERNAL_FUNCTION_PARAMETERS, ' - . self::TYPE_OBJECT . ' &this_, ' - . self::TYPE_ARGS . ' &vars_) ' . - '-> ' . self::TYPE_VAR . ' {' . PHP_EOL; + . Type::OBJECT . ' &this_, ' + . Type::ARGS . ' &vars_) ' . + '-> ' . Type::VAR . ' {' . PHP_EOL; $oriContext = $this->context; $this->context = new FunctionContext(); @@ -125,14 +127,14 @@ trait ClosureGenerator $var = $this->parseIdentifier($param->var); $phpName = is_string($param->var->name) ? $param->var->name : $this->unescapeVarName($var); if ($param->variadic) { - $code .= $this->getIndent() . self::TYPE_ARRAY . ' ' . $var . ';' . PHP_EOL; + $code .= $this->getIndent() . Type::ARRAY . ' ' . $var . ';' . PHP_EOL; $code .= $this->getIndent() . 'for (uint32_t i = ' . $i . '; i < php::getCallArgNum(); i++) {' . PHP_EOL; $this->indentLevel++; $code .= $this->getIndent() . $var . '.append(php::getCallArg(i));' . PHP_EOL; $this->indentLevel--; $code .= $this->getIndent() . '}' . PHP_EOL; $code .= $this->genExtraNamedVariadicArgs($var); - $this->addArgument($var, self::TYPE_ARRAY); + $this->addArgument($var, Type::ARRAY); $code .= $this->genClosureParamTypeCheck($param, $var, $phpName, $i, true); continue; } @@ -140,18 +142,18 @@ trait ClosureGenerator ? 'php::getCallArg(' . $i . ')' : 'php::getCallArg(' . $i . ', ' . $this->parseParamDefaultValue($param->default) . ')'; $code .= $this->getIndent() . 'auto ' . $var . ' = ' . $argExpr . ';' . PHP_EOL; - $this->addArgument($var, self::TYPE_VAR); + $this->addArgument($var, Type::VAR); $code .= $this->genClosureParamTypeCheck($param, $var, $phpName, $i, false); } foreach ($uses as $i => $useItem) { $var = $this->parseIdentifier($useItem->var); $code .= 'auto ' . $var . ' = vars_.get(' . $i . ');' . PHP_EOL; - $this->addArgument($var, self::TYPE_VAR); + $this->addArgument($var, Type::VAR); } if ($this->methodDef) { - $this->addArgument('this_', self::TYPE_OBJECT); + $this->addArgument('this_', Type::OBJECT); } $body = $this->genClosureBody($expr); @@ -171,7 +173,7 @@ trait ClosureGenerator if ($useItem->byRef) { // 闭包的 use 语法,若为引用类型,可以就地创建变量 if (!isset($oriContext->localVars[$var])) { - $oriContext->localVars[$var] = self::TYPE_REF; + $oriContext->localVars[$var] = Type::REF; } $useVars[] = $this->convertToRef($useItem->var); } else { @@ -221,11 +223,11 @@ trait ClosureGenerator } if ($this->isCallExpr($expr->expr)) { $nativeCall = $expr->expr->getAttribute('nativeCall'); - if ($nativeCall and $this->getFunction($nativeCall)->returnType === self::TYPE_VOID) { + if ($nativeCall and $this->getFunction($nativeCall)->returnType === Type::VOID) { return $this->genArrowFunctionVoidReturn($beforeCode, $code); } } - if ($this->detectTypeOfExpr($expr->expr) === self::TYPE_VOID) { + if ($this->detectTypeOfExpr($expr->expr) === Type::VOID) { return $this->genArrowFunctionVoidReturn($beforeCode, $code); } return $beforeCode . PHP_EOL . $this->genClosureReturnValue($code); @@ -260,7 +262,7 @@ trait ClosureGenerator $argInfo = new ArgInfo(); $argInfo->name = $var; $argInfo->phpName = $phpName; - $argInfo->type = self::TYPE_VAR; + $argInfo->type = Type::VAR; $argInfo->variadic = $variadic; $argInfo->typeCheck = $typeInfo['check']; $argInfo->typeStr = $typeInfo['typeStr']; diff --git a/src/Generator/DefaultArgumentGenerator.php b/src/Generator/DefaultArgumentGenerator.php index e5717c68..6a095ea7 100644 --- a/src/Generator/DefaultArgumentGenerator.php +++ b/src/Generator/DefaultArgumentGenerator.php @@ -7,6 +7,8 @@ namespace TypePhp\Generator; +use TypePhp\Type; + use TypePhp\Entity\ArgInfo; use TypePhp\Entity\ArrayInitPlan; use TypePhp\Entity\FunctionDef; @@ -16,8 +18,8 @@ trait DefaultArgumentGenerator protected function getDefaultArgumentType(ArgInfo $argInfo): string { $type = $argInfo->type; - if ($type === self::TYPE_STREAM || $type === self::TYPE_BOX) { - return self::TYPE_VAR; + if ($type === Type::STREAM || $type === Type::BOX) { + return Type::VAR; } return $type; } diff --git a/src/Generator/FiberGenerator.php b/src/Generator/FiberGenerator.php index a0d0c724..7250b289 100644 --- a/src/Generator/FiberGenerator.php +++ b/src/Generator/FiberGenerator.php @@ -8,6 +8,8 @@ namespace TypePhp\Generator; +use TypePhp\Type; + use PhpParser\Node; use PhpParser\Node\Expr\Yield_; use PhpParser\Node\Expr\YieldFrom; @@ -71,7 +73,7 @@ trait FiberGenerator $this->fatalError($v, 'Generator return type must accept TypePHP\\FiberGenerator; use Iterator, Traversable, iterable, object, mixed, or omit the return type'); } $functionDef->generator = true; - $functionDef->returnType = self::TYPE_VAR; + $functionDef->returnType = Type::VAR; $functionDef->returnClass = ''; $functionDef->returnTypeCheck = null; $functionDef->returnTypeStr = ''; @@ -126,7 +128,7 @@ trait FiberGenerator { $payload = $this->genYieldPayload($expr); $closed = $this->genTmpVarName(); - $this->addLocalVar($closed, self::TYPE_BOOL); + $this->addLocalVar($closed, Type::BOOL); return $closed . ' = false;' . PHP_EOL . $this->getIndent() . $closed . ' = typephp_fiber_yield(' . $payload . ');' . PHP_EOL . $this->getIndent() . 'if (' . $closed . ') {' . PHP_EOL @@ -137,7 +139,7 @@ trait FiberGenerator protected function parseYieldFromStmt(YieldFrom $expr): string { $closed = $this->genTmpVarName(); - $this->addLocalVar($closed, self::TYPE_BOOL); + $this->addLocalVar($closed, Type::BOOL); return $closed . ' = false;' . PHP_EOL . $this->getIndent() . 'typephp_fiber_yield_from(' . $this->parseExprAsValue($expr->expr) . ', &' . $closed . ');' . PHP_EOL . $this->getIndent() . 'if (' . $closed . ') {' . PHP_EOL @@ -180,9 +182,9 @@ trait FiberGenerator private function doGenFiberGeneratorFunction(Function_|ClassMethod $v, FunctionDef $functionDef, string $nativeName): string { - $functionDeclCode = self::TYPE_VAR . ' ' . self::PREFIX . $nativeName . '('; + $functionDeclCode = Type::VAR . ' ' . self::PREFIX . $nativeName . '('; if ($this->class) { - $functionDeclCode .= self::TYPE_OBJECT . ' &this_'; + $functionDeclCode .= Type::OBJECT . ' &this_'; if ($functionDef->params) { $functionDeclCode .= ', '; } @@ -210,8 +212,8 @@ trait FiberGenerator $closureVar = $this->genTmpVarName(); $code .= $this->getIndent() . 'php::ClosureFn ' . $closureVar . ' = [](' . 'INTERNAL_FUNCTION_PARAMETERS, ' - . self::TYPE_OBJECT . ' &this_, ' - . self::TYPE_ARGS . ' &vars_) -> ' . self::TYPE_VAR . ' {' . PHP_EOL; + . Type::OBJECT . ' &this_, ' + . Type::ARGS . ' &vars_) -> ' . Type::VAR . ' {' . PHP_EOL; $outerContext = $this->context; $outerIndent = $this->indentLevel; @@ -222,11 +224,11 @@ trait FiberGenerator $this->indentLevel++; foreach ($functionDef->argInfoList as $i => $argInfo) { - $code .= $this->getIndent() . self::TYPE_VAR . ' ' . $argInfo->name . ' = vars_.get(' . $i . ');' . PHP_EOL; - $this->addArgument($argInfo->name, self::TYPE_VAR); + $code .= $this->getIndent() . Type::VAR . ' ' . $argInfo->name . ' = vars_.get(' . $i . ');' . PHP_EOL; + $this->addArgument($argInfo->name, Type::VAR); } if ($this->class) { - $this->addArgument('this_', self::TYPE_OBJECT); + $this->addArgument('this_', Type::OBJECT); } $body = ''; diff --git a/src/Generator/TypeCheckGenerator.php b/src/Generator/TypeCheckGenerator.php index 6346d87b..07d45cb2 100644 --- a/src/Generator/TypeCheckGenerator.php +++ b/src/Generator/TypeCheckGenerator.php @@ -8,6 +8,8 @@ namespace TypePhp\Generator; +use TypePhp\Type; + use TypePhp\Entity\ArgInfo; use PhpParser\Node; use PhpParser\Node\IntersectionType; @@ -284,7 +286,7 @@ trait TypeCheckGenerator $code = $this->getIndent() . 'for (auto ' . $iterVar . ' = ' . $argInfo->name . '.begin(); ' . $iterVar . ' != ' . $argInfo->name . '.end(); ++' . $iterVar . ') {' . PHP_EOL; $this->indentLevel++; - $code .= $this->getIndent() . self::TYPE_VAR . ' ' . $valueVar . ' = ' . $iterVar . '.value();' . PHP_EOL; + $code .= $this->getIndent() . Type::VAR . ' ' . $valueVar . ' = ' . $iterVar . '.value();' . PHP_EOL; if ($this->compositeTypeNeedsIntToFloatCoercion($argInfo->typeCheck)) { $code .= $this->getIndent() . 'if (' . $valueVar . '.isInt()) {' . PHP_EOL; $this->indentLevel++; @@ -293,7 +295,7 @@ trait TypeCheckGenerator $this->indentLevel--; $code .= $this->getIndent() . '}' . PHP_EOL; } - $code .= $this->getIndent() . self::TYPE_INT . ' ' . $argNoVar . ' = ' . ($argIndex + 1) . ' + ' . $iterVar . '.index();' . PHP_EOL; + $code .= $this->getIndent() . Type::INT . ' ' . $argNoVar . ' = ' . ($argIndex + 1) . ' + ' . $iterVar . '.index();' . PHP_EOL; $code .= $this->getIndent() . 'if (UNEXPECTED(!(' . $orExpr . '))) {' . PHP_EOL; $this->indentLevel++; $code .= $this->getIndent() . 'php::throwException(zend_ce_type_error, (' . $msgExpr . ').toCString());' . PHP_EOL; @@ -411,7 +413,7 @@ trait TypeCheckGenerator $code = $this->getIndent() . 'for (auto ' . $iterVar . ' = ' . $argInfo->name . '.begin(); ' . $iterVar . ' != ' . $argInfo->name . '.end(); ++' . $iterVar . ') {' . PHP_EOL; $this->indentLevel++; - $code .= $this->getIndent() . self::TYPE_VAR . ' ' . $valueVar . ' = ' . $iterVar . '.value();' . PHP_EOL; + $code .= $this->getIndent() . Type::VAR . ' ' . $valueVar . ' = ' . $iterVar . '.value();' . PHP_EOL; if ($this->compositeTypeNeedsIntToFloatCoercion($argInfo->typeCheck)) { $code .= $this->getIndent() . 'if (' . $valueVar . '.isInt()) {' . PHP_EOL; $this->indentLevel++; @@ -420,7 +422,7 @@ trait TypeCheckGenerator $this->indentLevel--; $code .= $this->getIndent() . '}' . PHP_EOL; } - $code .= $this->getIndent() . self::TYPE_INT . ' ' . $argNoVar . ' = ' . ($argIndex + 1) . ' + ' . $iterVar . '.index();' . PHP_EOL; + $code .= $this->getIndent() . Type::INT . ' ' . $argNoVar . ' = ' . ($argIndex + 1) . ' + ' . $iterVar . '.index();' . PHP_EOL; $code .= $this->getIndent() . 'if (UNEXPECTED(!(' . $orExpr . '))) {' . PHP_EOL; $this->indentLevel++; $code .= $this->getIndent() . 'return php::throwException(zend_ce_type_error, (' . $msgExpr . ').toCString());' . PHP_EOL; diff --git a/src/Generator/Utils.php b/src/Generator/Utils.php index 85a4ae48..1b14f62d 100644 --- a/src/Generator/Utils.php +++ b/src/Generator/Utils.php @@ -8,7 +8,8 @@ namespace TypePhp\Generator; -use TypePhp\CompilerBase; +use TypePhp\Type; + use TypePhp\Metadata\Constants; trait Utils @@ -54,7 +55,7 @@ trait Utils protected function genArray(array $elements): string { - return CompilerBase::TYPE_ARRAY . '{' . implode(', ', $elements) . ' }'; + return Type::ARRAY . '{' . implode(', ', $elements) . ' }'; } protected function genRawStr(string $str): string diff --git a/src/Optimizer/FuncCallOptimizer.php b/src/Optimizer/FuncCallOptimizer.php index 93fdf71e..3adda99a 100644 --- a/src/Optimizer/FuncCallOptimizer.php +++ b/src/Optimizer/FuncCallOptimizer.php @@ -8,6 +8,8 @@ namespace TypePhp\Optimizer; +use TypePhp\Type; + use TypePhp\Resolver\Reflection; use PhpParser\Node; @@ -126,28 +128,28 @@ trait FuncCallOptimizer // Big* dispatch 'abs' => ['bigDispatch' => [ - self::TYPE_BIGINT => 'php::BigInt::abs', - self::TYPE_BIGFLOAT => 'php::BigFloat::abs', - self::TYPE_DECIMAL => 'php::Decimal::abs', + Type::BIGINT => 'php::BigInt::abs', + Type::BIGFLOAT => 'php::BigFloat::abs', + Type::DECIMAL => 'php::Decimal::abs', 'fallback' => 'php::fn::abs', ]], 'pow' => ['bigDispatch' => [ - self::TYPE_BIGINT => 'php::BigInt::pow', - self::TYPE_DECIMAL => 'php::Decimal::pow', + Type::BIGINT => 'php::BigInt::pow', + Type::DECIMAL => 'php::Decimal::pow', 'fallback' => 'php::fn::pow', ]], 'sqrt' => ['bigDispatch' => [ - self::TYPE_BIGINT => 'php::BigInt::sqrt', - self::TYPE_DECIMAL => 'php::Decimal::sqrt', - self::TYPE_BIGFLOAT => 'php::BigFloat::sqrt', + Type::BIGINT => 'php::BigInt::sqrt', + Type::DECIMAL => 'php::Decimal::sqrt', + Type::BIGFLOAT => 'php::BigFloat::sqrt', 'fallback' => 'php::fn::sqrt', ]], 'floor' => ['bigDispatch' => [ - self::TYPE_DECIMAL => 'php::Decimal::floor', + Type::DECIMAL => 'php::Decimal::floor', 'fallback' => 'php::fn::floor', ]], 'ceil' => ['bigDispatch' => [ - self::TYPE_DECIMAL => 'php::Decimal::ceil', + Type::DECIMAL => 'php::Decimal::ceil', 'fallback' => 'php::fn::ceil', ]], @@ -158,9 +160,9 @@ trait FuncCallOptimizer 'boolval' => ['conversion' => self::ARG_TYPE_BOOL], // SSA compile-time type checks - 'is_int' => ['constFold' => self::FOLD_SSA_TYPE, 'constFoldExtra' => self::TYPE_INT], - 'is_float' => ['constFold' => self::FOLD_SSA_TYPE, 'constFoldExtra' => self::TYPE_FLOAT], - 'is_bool' => ['constFold' => self::FOLD_SSA_TYPE, 'constFoldExtra' => self::TYPE_BOOL], + 'is_int' => ['constFold' => self::FOLD_SSA_TYPE, 'constFoldExtra' => Type::INT], + 'is_float' => ['constFold' => self::FOLD_SSA_TYPE, 'constFoldExtra' => Type::FLOAT], + 'is_bool' => ['constFold' => self::FOLD_SSA_TYPE, 'constFoldExtra' => Type::BOOL], // Custom handlers 'is_null' => ['handler' => 'genIsNull'], @@ -474,9 +476,9 @@ trait FuncCallOptimizer if ($convType === self::ARG_TYPE_STR) { return match ($type) { - self::TYPE_BIGINT => 'php::BigInt::toString(' . $parsed . ')', - self::TYPE_BIGFLOAT => 'php::BigFloat::toString(' . $parsed . ')', - self::TYPE_DECIMAL => 'php::Decimal::toString(' . $parsed . ')', + Type::BIGINT => 'php::BigInt::toString(' . $parsed . ')', + Type::BIGFLOAT => 'php::BigFloat::toString(' . $parsed . ')', + Type::DECIMAL => 'php::Decimal::toString(' . $parsed . ')', default => $this->convertStringExpr($parsed), }; } @@ -692,7 +694,7 @@ trait FuncCallOptimizer protected function genRound(string $n, Node\Expr\FuncCall $e, array $c): string { $type = $this->detectTypeOfExpr($e->args[0]->value); - if ($type === self::TYPE_DECIMAL) { + if ($type === Type::DECIMAL) { $a0 = $this->parseExpr($e->args[0]->value); if (count($e->args) >= 2) { return 'php::Decimal::round(' . $a0 . ', ' . $this->parseExpr($e->args[1]->value) . ')'; @@ -743,7 +745,7 @@ trait FuncCallOptimizer $list = []; foreach ($funcDef->argInfoList as $i => $argInfo) { if ($argInfo->variadic) { - $tmpVar = $this->addTmpVar(self::TYPE_ARRAY); + $tmpVar = $this->addTmpVar(Type::ARRAY); $this->context->beforeStmtLines[] = $this->genArray($list) . ';'; $this->context->beforeStmtLines[] = $tmpVar . '.merge(' . $argInfo->name . ');'; return $tmpVar; diff --git a/src/Optimizer/LoopVarOptimizer.php b/src/Optimizer/LoopVarOptimizer.php index 94804a45..10bd45a5 100644 --- a/src/Optimizer/LoopVarOptimizer.php +++ b/src/Optimizer/LoopVarOptimizer.php @@ -10,6 +10,8 @@ namespace TypePhp\Optimizer; +use TypePhp\Type; + use TypePhp\Analysis\SsaBuilder; use TypePhp\Analysis\SsaFlags; use PhpParser\Node; @@ -62,7 +64,7 @@ trait LoopVarOptimizer if ($depFailed) { continue; } - $this->context->localVars[$escapedName] = self::TYPE_INT; + $this->context->localVars[$escapedName] = Type::INT; } } @@ -386,7 +388,7 @@ trait LoopVarOptimizer return false; } - return $this->detectTypeOfExpr($expr) === self::TYPE_INT; + return $this->detectTypeOfExpr($expr) === Type::INT; } protected function isLoopKnownNonNegativeIntCall(NodeAbstract $expr): bool diff --git a/src/Optimizer/SsaPropOptimizer.php b/src/Optimizer/SsaPropOptimizer.php index c2cde4c4..53de7828 100644 --- a/src/Optimizer/SsaPropOptimizer.php +++ b/src/Optimizer/SsaPropOptimizer.php @@ -24,6 +24,8 @@ namespace TypePhp\Optimizer; +use TypePhp\Type; + use TypePhp\Analysis\SsaBuilder; use TypePhp\Analysis\SsaFlags; use TypePhp\Resolver\Reflection; @@ -779,18 +781,18 @@ trait SsaPropOptimizer */ protected function getHoistedObjectPropInfo(string $declaredType): array { - if ($declaredType === self::TYPE_INT || $declaredType === self::TYPE_FLOAT) { + if ($declaredType === Type::INT || $declaredType === Type::FLOAT) { return ['type' => $declaredType, 'kind' => 'zval']; } - return ['type' => self::TYPE_VAR, 'kind' => 'var']; + return ['type' => Type::VAR, 'kind' => 'var']; } protected function getZvalValueMacroForPropType(string $type): ?string { return match ($type) { - self::TYPE_INT => 'Z_LVAL_P', - self::TYPE_FLOAT => 'Z_DVAL_P', + Type::INT => 'Z_LVAL_P', + Type::FLOAT => 'Z_DVAL_P', default => null, }; } @@ -825,7 +827,7 @@ trait SsaPropOptimizer if ($zvalMacro !== null) { $this->context->beforeStmtLines[] = $cType . ' &' . $propVar . ' = ' . $zvalMacro . '(' . $refGetter . '.unwrap_ptr());'; } else { - $this->context->beforeStmtLines[] = self::TYPE_VAR . ' ' . $propVar . ' = ' . $refGetter . ';'; + $this->context->beforeStmtLines[] = Type::VAR . ' ' . $propVar . ' = ' . $refGetter . ';'; } $this->context->hoistedProps[$objName][$propName] = true; diff --git a/src/Optimizer/SsaTypeOptimizer.php b/src/Optimizer/SsaTypeOptimizer.php index 1fb41385..b8907422 100644 --- a/src/Optimizer/SsaTypeOptimizer.php +++ b/src/Optimizer/SsaTypeOptimizer.php @@ -9,6 +9,8 @@ namespace TypePhp\Optimizer; +use TypePhp\Type; + use TypePhp\Analysis\SsaBuilder; use TypePhp\Analysis\SsaFlags; use TypePhp\Analysis\SsaVar; @@ -78,8 +80,8 @@ trait SsaTypeOptimizer } $narrowableTypes = [ - self::TYPE_INT => true, - self::TYPE_FLOAT => true, + Type::INT => true, + Type::FLOAT => true, ]; // Group SSA vars by original variable name @@ -100,7 +102,7 @@ trait SsaTypeOptimizer foreach (array_keys($groups) as $name) { $varName = $this->escapeVarName($name); if (!isset($this->context->arguments[$varName]) && !$this->hasVar($varName)) { - $this->context->localVars[$varName] = self::TYPE_VAR; + $this->context->localVars[$varName] = Type::VAR; } } @@ -141,7 +143,7 @@ trait SsaTypeOptimizer $nonNarrowableType = $defType; } elseif ($nonNarrowableType !== $defType) { // Mixed non-narrowable types — can't determine a single type - $nonNarrowableType = self::TYPE_VAR; + $nonNarrowableType = Type::VAR; } continue; } @@ -160,7 +162,7 @@ trait SsaTypeOptimizer // Mixed narrowable and non-narrowable types (e.g. $x = [1,2] then $x = 42) // — can't safely narrow. - if ($narrowedType !== null && $nonNarrowableType !== null && $nonNarrowableType !== self::TYPE_VAR) { + if ($narrowedType !== null && $nonNarrowableType !== null && $nonNarrowableType !== Type::VAR) { continue; } @@ -169,7 +171,7 @@ trait SsaTypeOptimizer // SSA variables can resolve them (these types have no extra metadata). if ( $nonNarrowableType !== null - && in_array($nonNarrowableType, [self::TYPE_BIGINT, self::TYPE_DECIMAL, self::TYPE_BIGFLOAT, self::TYPE_STREAM], true) + && in_array($nonNarrowableType, [Type::BIGINT, Type::DECIMAL, Type::BIGFLOAT, Type::STREAM], true) ) { $this->context->localVars[$varName] = $nonNarrowableType; } @@ -179,10 +181,10 @@ trait SsaTypeOptimizer // Scan for operations that SSA definition types alone can't detect $functionStmts = $ssa->getStmts(); if ($functionStmts) { - if ($narrowedType === self::TYPE_INT && $this->hasDangerousIntOps($varName, $functionStmts)) { + if ($narrowedType === Type::INT && $this->hasDangerousIntOps($varName, $functionStmts)) { continue; } - if ($narrowedType === self::TYPE_FLOAT && $this->hasDangerousFloatOps($varName, $functionStmts)) { + if ($narrowedType === Type::FLOAT && $this->hasDangerousFloatOps($varName, $functionStmts)) { continue; } } @@ -211,7 +213,7 @@ trait SsaTypeOptimizer if ($def instanceof Node\Stmt\Expression && $def->expr instanceof Node\Expr\Assign) { $expr = $def->expr->expr; $type = $this->detectTypeOfExpr($expr); - if ($type === self::TYPE_INT && !$this->isSafeSsaIntExpr($expr)) { + if ($type === Type::INT && !$this->isSafeSsaIntExpr($expr)) { return null; } return $type; @@ -232,7 +234,7 @@ trait SsaTypeOptimizer } if ($def instanceof Node\Stmt\Catch_) { - return self::TYPE_OBJECT; + return Type::OBJECT; } if ($def instanceof Node\Stmt\Static_) { @@ -250,11 +252,11 @@ trait SsaTypeOptimizer protected function detectAssignOpDefType(Node\Expr\AssignOp $expr): ?string { if ($expr instanceof Node\Expr\AssignOp\Div) { - return self::TYPE_FLOAT; + return Type::FLOAT; } if ($expr instanceof Node\Expr\AssignOp\Concat) { - return self::TYPE_STR; + return Type::STR; } if ($expr instanceof Node\Expr\AssignOp\Pow) { @@ -265,10 +267,10 @@ trait SsaTypeOptimizer || $expr instanceof Node\Expr\AssignOp\Minus || $expr instanceof Node\Expr\AssignOp\Mul) { $rhsType = $this->detectTypeOfExpr($expr->expr); - if ($rhsType === self::TYPE_FLOAT) { - return self::TYPE_FLOAT; + if ($rhsType === Type::FLOAT) { + return Type::FLOAT; } - if ($rhsType === self::TYPE_INT) { + if ($rhsType === Type::INT) { return null; } return $rhsType; @@ -292,7 +294,7 @@ trait SsaTypeOptimizer } if ($expr instanceof Node\Expr\ConstFetch) { - return $this->detectConstType($expr) === self::TYPE_INT; + return $this->detectConstType($expr) === Type::INT; } if ($expr instanceof Node\Expr\BitwiseNot) { diff --git a/src/Parser/ArrayExpressionTrait.php b/src/Parser/ArrayExpressionTrait.php index 4a6728f2..4a09ab8c 100644 --- a/src/Parser/ArrayExpressionTrait.php +++ b/src/Parser/ArrayExpressionTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\NodeAbstract; @@ -18,7 +20,7 @@ trait ArrayExpressionTrait $items = $node->items; // 优化代码风格,空数组直接返回{},否则会产生一些空洞内容 if (count($items) === 0) { - return self::TYPE_ARRAY . '{}'; + return Type::ARRAY . '{}'; } $hasKey = false; @@ -58,14 +60,14 @@ trait ArrayExpressionTrait if ($item->key) { $this->assertExprCanBeUsedAsValue($item->key, 'array key'); $key = $this->parseArrayKey($item->key); - $list[] = $this->getIndent() . '{ ' . $key . ', ' . self::TYPE_VAR . '(' . $value . ') }'; + $list[] = $this->getIndent() . '{ ' . $key . ', ' . Type::VAR . '(' . $value . ') }'; } else { - $list[] = $this->getIndent() . self::TYPE_VAR . '(' . $value . ')'; + $list[] = $this->getIndent() . Type::VAR . '(' . $value . ')'; } } $this->indentLevel--; - return self::TYPE_ARRAY . '{' . PHP_EOL . + return Type::ARRAY . '{' . PHP_EOL . implode(', ' . PHP_EOL, $list) . PHP_EOL . $this->getIndent() . '}'; @@ -83,10 +85,10 @@ trait ArrayExpressionTrait if ($this->isScalarString($node->dim)) { $name = $node->dim->value; if (!$this->hasGlobalVar($name)) { - $this->addGlobalVar($name, self::TYPE_VAR); + $this->addGlobalVar($name, Type::VAR); } if (!$this->hasScopeGlobalVar($name)) { - $this->addScopeGlobalVar($name, self::TYPE_VAR); + $this->addScopeGlobalVar($name, Type::VAR); } return $name; } @@ -170,17 +172,17 @@ trait ArrayExpressionTrait } if (!$this->hasVar($var)) { if ($write) { - $this->addLocalVar($var, self::TYPE_ARRAY); + $this->addLocalVar($var, Type::ARRAY); } else { $this->errorUndefinedVariable($node->var); } } else { $type = $this->getVarType($var); - if ($type === self::TYPE_BOOL || $type === self::TYPE_INT || $type === self::TYPE_FLOAT) { + if ($type === Type::BOOL || $type === Type::INT || $type === Type::FLOAT) { $this->fatalError($node, 'Cannot use [] for numbers'); } } - if ($this->getVarType($var) === self::TYPE_STR) { + if ($this->getVarType($var) === Type::STR) { if ($node->dim === null) { $this->fatalError($node, 'Cannot use [] for strings'); } @@ -206,7 +208,7 @@ trait ArrayExpressionTrait private function parseArrayMixed(Expr\Array_ $node): string { $tmpVar = $this->genTmpVarName(); - $this->addLocalVar($tmpVar, self::TYPE_ARRAY); + $this->addLocalVar($tmpVar, Type::ARRAY); // 释放临时变量,避免修改数组产生数组复制操作 $this->context->beforeStmtLines[] = $this->getIndent() . $tmpVar . '.clean();'; diff --git a/src/Parser/AssignOpTrait.php b/src/Parser/AssignOpTrait.php index 278ab52d..d006e6bb 100644 --- a/src/Parser/AssignOpTrait.php +++ b/src/Parser/AssignOpTrait.php @@ -8,6 +8,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use TypePhp\Resolver\PropertyWriteTarget; use PhpParser\Node; use PhpParser\Node\ArrayItem; @@ -26,19 +28,19 @@ trait AssignOpTrait $target = $this->parseGlobalsArrayDimFetch($left); $value = $this->parseExprAsValue($right); $tmp = $this->genTmpVarName(); - $this->addLocalVar($tmp, self::TYPE_VAR); + $this->addLocalVar($tmp, Type::VAR); return '((' . $tmp . ' = ' . $value . ', ' . $target . ' = ' . $tmp . '), ' . $tmp . ')'; } $array = $this->parseWritableIdentifier($left->var); $code = ''; if (!$this->hasVar($array) and $this->isVarExpr($left->var)) { - $this->addLocalVar($array, self::TYPE_ARRAY); + $this->addLocalVar($array, Type::ARRAY); } $value = $this->parseExprAsValue($right); $tmp = $this->genTmpVarName(); - $this->addLocalVar($tmp, self::TYPE_VAR); + $this->addLocalVar($tmp, Type::VAR); if ($left->dim === null) { return $code . '((' . $tmp . ' = ' . $value . ', ' . "{$array}.offsetSet(" . self::VALUE_NULL . ", {$tmp})" . '), ' . $tmp . ')'; @@ -62,7 +64,7 @@ trait AssignOpTrait } $tmp = $this->genTmpVarName(); - $this->addLocalVar($tmp, self::TYPE_VAR); + $this->addLocalVar($tmp, Type::VAR); // Comma expression: store RHS → execute side effect → evaluate to stored value return '((' . $tmp . ' = ' . $rightExpr . ', ' . $this->emitDynamicPropertyFetchWrite($left, $tmp, $target) . '), ' . $tmp . ')'; } @@ -77,7 +79,7 @@ trait AssignOpTrait $next = $next->expr; } $tmpVar = $this->genTmpVarName(); - $this->addLocalVar($tmpVar, self::TYPE_VAR); + $this->addLocalVar($tmpVar, Type::VAR); // 翻转赋值链 $chain = array_reverse($chain); @@ -108,7 +110,7 @@ trait AssignOpTrait $code = '{'; $this->indentLevel++; $tmpVar = $this->genTmpVarName(); - $this->addLocalVar($tmpVar, self::TYPE_VAR); + $this->addLocalVar($tmpVar, Type::VAR); $code .= $this->getIndent() . $tmpVar . ' = ' . $this->parseExpr($right) . '; '; foreach ($items as $k => $item) { if (!$item) { @@ -118,13 +120,13 @@ trait AssignOpTrait $key = $item->key ? $this->parseArrayKey($item->key) : (string) $k; if ($item->value instanceof Expr\List_) { $nestedTmp = $this->genTmpVarName(); - $this->addLocalVar($nestedTmp, self::TYPE_ARRAY); + $this->addLocalVar($nestedTmp, Type::ARRAY); $code .= "{$nestedTmp} = {$tmpVar}.item({$key}); "; $code .= $this->parseAssignToList($item->value, new Variable($nestedTmp)); } else { $var = $this->parseWritableIdentifier($item->value); if ($this->isVarExpr($item->value) and !$this->hasVar($var)) { - $this->addLocalVar($var, self::TYPE_VAR); + $this->addLocalVar($var, Type::VAR); } $code .= "{$var} = {$tmpVar}.item({$key}); "; } @@ -148,8 +150,8 @@ trait AssignOpTrait $type = $this->detectTypeOfExpr($right); $finalVarType = $this->getNormalAssignType($type); $runtimeObjectAssignClass = ''; - if ($type === self::TYPE_VOID) { - $type = self::TYPE_VAR; + if ($type === Type::VOID) { + $type = Type::VAR; } if ($left instanceof Expr\PropertyFetch && ($setter = $this->getPropertyHookSetter($left)) !== null) { @@ -179,7 +181,7 @@ trait AssignOpTrait // 右值是一个对象,已获得类的名称,左值必须与右值的类一致 if ($rightClass) { if (!$this->hasVar($var)) { - $this->addLocalVar($var, self::TYPE_OBJECT); + $this->addLocalVar($var, Type::OBJECT); $this->addObject($var, $rightClass); } elseif (($leftClass = $this->getDeclaredObjectType($var)) !== '') { if ($this->isObjectClassStaticallyAssignableTo($rightClass, $leftClass)) { @@ -194,7 +196,7 @@ trait AssignOpTrait $this->fatalError($left, "Cannot re-assign typed object `\${$var}` from `{$leftClass}` to `{$rightClass}`"); } } else { - $this->checkVarAssignExpr($left, $this->getVarType($var), self::TYPE_OBJECT); + $this->checkVarAssignExpr($left, $this->getVarType($var), Type::OBJECT); } } else { if ($this->isMethodCall($right) and $this->isNamedMethod($right->name)) { @@ -210,7 +212,7 @@ trait AssignOpTrait } } if ($this->isFuncCallExpr($right) and $this->isNameExpr($right->name)) { - $type = $type === self::TYPE_VOID ? self::TYPE_VAR : $type; + $type = $type === Type::VOID ? Type::VAR : $type; } elseif ($this->isStaticCall($right) and $this->isNameExpr($right->class) and $this->isIdExpr($right->name)) { $class = $this->parseIdentifier($right->class); if ($class === 'std') { @@ -222,18 +224,18 @@ trait AssignOpTrait $this->fatalError($left, "Must create std::{$right->name->toString()} in the top-level scope of the function"); } if ($right->name->toString() === 'array') { - $this->addLocalVar($var, self::TYPE_STD_ARRAY); + $this->addLocalVar($var, Type::STD_ARRAY); return $this->parseStdArray($var, $right); } if ($right->name->toString() === 'vector') { - $this->addLocalVar($var, self::TYPE_STD_VECTOR); + $this->addLocalVar($var, Type::STD_VECTOR); return $this->parseStdVector($var, $right); } if ($right->name->toString() === 'map') { - $this->addLocalVar($var, self::TYPE_STD_MAP); + $this->addLocalVar($var, Type::STD_MAP); return $this->parseStdMap($var, $right); } - $this->addLocalVar($var, self::TYPE_STD_ORDERED_MAP); + $this->addLocalVar($var, Type::STD_ORDERED_MAP); return $this->parseStdOrderedMap($var, $right); } else { $valueExpr = $this->parseStdCall($right); @@ -246,7 +248,7 @@ trait AssignOpTrait } } elseif ($this->isVarExpr($right)) { $rightVar = $this->parseIdentifier($right); - $type = $this->isStdContainer($rightVar) ? self::TYPE_ARRAY : $this->getVarType($rightVar); + $type = $this->isStdContainer($rightVar) ? Type::ARRAY : $this->getVarType($rightVar); $finalVarType = $this->getNormalAssignType($type); $leftClass = $this->getDeclaredObjectType($var); $rightClass = $this->getDeclaredObjectType($rightVar); @@ -269,7 +271,7 @@ trait AssignOpTrait $finalVarType = $this->getVarType($var); $this->checkVarAssignExpr($left, $finalVarType, $type); $declaredObjectClass = $this->getDeclaredObjectType($var); - if ($finalVarType === self::TYPE_OBJECT && $declaredObjectClass !== '' && ($type === self::TYPE_VAR || $type === self::TYPE_OBJECT)) { + if ($finalVarType === Type::OBJECT && $declaredObjectClass !== '' && ($type === Type::VAR || $type === Type::OBJECT)) { $runtimeObjectAssignClass = $declaredObjectClass; } } @@ -278,7 +280,7 @@ trait AssignOpTrait return $this->parseAssignPropertyFetch($left, $right, $propertyWriteTarget); } elseif ($this->isArrayDimFetch($left) and $this->isVarExpr($left->var)) { $tmp = $this->parseIdentifier($left->var); - if ($this->getVarType($tmp) === self::TYPE_STR and $left->dim === null) { + if ($this->getVarType($tmp) === Type::STR and $left->dim === null) { $this->fatalError($left, 'Cannot use [] for strings'); } if ($this->isStdContainerExpr($left)) { @@ -304,12 +306,12 @@ trait AssignOpTrait $leftExprType = $this->detectTypeOfExpr($left); $rightExprType = $this->detectTypeOfExpr($right); if ($propertyWriteTarget !== null && ($propertyDef = $this->getNativePropertyDef($left)) !== null) { - $effectiveRightType = $rightExprType === self::TYPE_VAR && $this->getNativeScalarPropertyTypeCheckHelper($propertyDef) !== null + $effectiveRightType = $rightExprType === Type::VAR && $this->getNativeScalarPropertyTypeCheckHelper($propertyDef) !== null ? $propertyDef->type : $rightExprType; return $var . ' = ' . $this->convertNativePropertyWriteExpr($propertyDef->type, $effectiveRightType, $rightExpr); } - if ($finalVarType === self::TYPE_VAR) { + if ($finalVarType === Type::VAR) { return $var . ' = ' . $rightExpr; } else { return $var . ' = ' . $this->convertExprType($rightExpr, $leftExprType, $rightExprType); @@ -330,7 +332,7 @@ trait AssignOpTrait $rightExpr = $this->wrapPropertyWriteTypeCheck($target, $right, $rightExpr); } $tmp = $this->genTmpVarName(); - $this->addLocalVar($tmp, self::TYPE_VAR); + $this->addLocalVar($tmp, Type::VAR); $call = $this->emitPropertyHookSetterCall($left, $setter, new Expr\Variable($tmp)); return '((' . $tmp . ' = ' . $rightExpr . ', ' . $call . '), ' . $tmp . ')'; } @@ -346,8 +348,8 @@ trait AssignOpTrait return false; } - return !in_array($def->type, [self::TYPE_INT, self::TYPE_FLOAT, self::TYPE_BOOL, self::TYPE_STR, self::TYPE_ARRAY], true) - && $rightType === self::TYPE_VAR; + return !in_array($def->type, [Type::INT, Type::FLOAT, Type::BOOL, Type::STR, Type::ARRAY], true) + && $rightType === Type::VAR; } protected function parseStdContainerCopyAssign(string $leftVar, Expr $right): ?string @@ -398,7 +400,7 @@ trait AssignOpTrait $right = $this->parseExprAsValue($node->expr); $read = $this->emitPropertyHookGetterCall($node->var, $getter); $tmp = $this->genTmpVarName(); - $this->addLocalVar($tmp, self::TYPE_VAR); + $this->addLocalVar($tmp, Type::VAR); $binaryOp = $this->removeAssignOp($op); $value = match ($binaryOp) { '.' => 'php::concat(' . $read . ', ' . $right . ')', @@ -428,7 +430,7 @@ trait AssignOpTrait // BigInt/BigDecimal/BigFloat are immutable Box types stored inside // php::Var — Variant::operator+= calls ZendVM add_function which // cannot handle them. We must generate `$v = Type::add($v, $x)`. - if ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) { + if ($type === Type::BIGINT || $type === Type::DECIMAL || $type === Type::BIGFLOAT) { return $this->parseBigAssignOp($node, $var, $type, $expr, $rightType, $op); } @@ -468,7 +470,7 @@ trait AssignOpTrait $this->context->beforeStmtLines[] = "{$tmpVar} = php::concat(" . $this->convertVarType($tmpVar, $readVar) . ', ' . $this->convertExprType($expr, $type, $rightType) . ');'; - } elseif ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) { + } elseif ($type === Type::BIGINT || $type === Type::DECIMAL || $type === Type::BIGFLOAT) { $bigAssign = $this->parseBigAssignOpExpr($readVar, $type, $expr, $rightType, $binaryOp, $node->var, $node->expr); $this->context->beforeStmtLines[] = "{$tmpVar} = {$bigAssign};"; } else { @@ -490,7 +492,7 @@ trait AssignOpTrait } $binaryOp = $this->removeAssignOp($op); $tmpVar = $this->genTmpVarName(); - $this->addLocalVar($tmpVar, self::TYPE_VAR); + $this->addLocalVar($tmpVar, Type::VAR); $readProperty = $this->emitDynamicPropertyFetchRead($node->var, $propertyWriteTarget); if ($this->isAssignOpConcat($op)) { $this->context->beforeStmtLines[] = "{$tmpVar} = php::concat({$readProperty}, {$expr});"; @@ -521,7 +523,7 @@ trait AssignOpTrait } $rightType = $this->detectTypeOfExpr($node->expr); - if ($this->isFixedObjectProp($def) && $rightType !== self::TYPE_VAR && !$this->canAssignStaticTypeToObjectProperty($def, $rightType)) { + if ($this->isFixedObjectProp($def) && $rightType !== Type::VAR && !$this->canAssignStaticTypeToObjectProperty($def, $rightType)) { $this->fatalError( $node->var, 'Cannot assign ' . $this->getPropertyAssignmentTypeName($rightType) @@ -535,15 +537,15 @@ trait AssignOpTrait $var = $this->parseWritableIdentifier($node->var); if (!$this->isNativePropertyTypedValue($node->var)) { - $helper = $def->type === self::TYPE_FLOAT ? 'typephp_static_float_ref' : 'typephp_static_int_ref'; + $helper = $def->type === Type::FLOAT ? 'typephp_static_float_ref' : 'typephp_static_int_ref'; $var = $helper . '(' . $var . '.unwrap_ptr())'; } $rightExpr = $this->parseIdentifier($node->expr); - if ($rightType === self::TYPE_VAR) { + if ($rightType === Type::VAR) { $rightExpr = $this->wrapObjectPropertyAssignTypeCheck($node->var, $node->expr, $rightExpr); } - $effectiveRightType = $rightType === self::TYPE_VAR && $this->getNativeScalarPropertyTypeCheckHelper($def) !== null + $effectiveRightType = $rightType === Type::VAR && $this->getNativeScalarPropertyTypeCheckHelper($def) !== null ? $def->type : $rightType; @@ -561,13 +563,13 @@ trait AssignOpTrait protected function canUseNativePropertyAssignOp(string $propertyType, string $rightType, string $op): bool { - if ($rightType !== self::TYPE_VAR && !($propertyType === $rightType || ($propertyType === self::TYPE_FLOAT && $rightType === self::TYPE_INT))) { + if ($rightType !== Type::VAR && !($propertyType === $rightType || ($propertyType === Type::FLOAT && $rightType === Type::INT))) { return false; } return match ($propertyType) { - self::TYPE_INT => in_array($op, ['+=', '-=', '*=', '%=', '<<=', '>>=', '&=', '|=', '^='], true), - self::TYPE_FLOAT => in_array($op, ['+=', '-=', '*=', '/='], true), + Type::INT => in_array($op, ['+=', '-=', '*=', '%=', '<<=', '>>=', '&=', '|=', '^='], true), + Type::FLOAT => in_array($op, ['+=', '-=', '*=', '/='], true), default => false, }; } @@ -582,9 +584,9 @@ trait AssignOpTrait protected function parseBigAssignOpExpr(string $leftExpr, string $leftType, string $rightExpr, string $rightType, string $binaryOp, NodeAbstract $errorNode, ?NodeAbstract $rightNode = null): string { [$class, $opMap] = match ($leftType) { - self::TYPE_BIGINT => ['BigInt', ['+' => 'add', '-' => 'sub', '*' => 'mul', '/' => 'div', '%' => 'mod', '&' => 'bitAnd', '|' => 'bitOr', '^' => 'bitXor', '<<' => 'bitShiftLeft', '>>' => 'bitShiftRight']], - self::TYPE_DECIMAL => ['Decimal', ['+' => 'add', '-' => 'sub', '*' => 'mul', '/' => 'div', '%' => 'mod']], - self::TYPE_BIGFLOAT => ['BigFloat', ['+' => 'add', '-' => 'sub', '*' => 'mul', '/' => 'div']], + Type::BIGINT => ['BigInt', ['+' => 'add', '-' => 'sub', '*' => 'mul', '/' => 'div', '%' => 'mod', '&' => 'bitAnd', '|' => 'bitOr', '^' => 'bitXor', '<<' => 'bitShiftLeft', '>>' => 'bitShiftRight']], + Type::DECIMAL => ['Decimal', ['+' => 'add', '-' => 'sub', '*' => 'mul', '/' => 'div', '%' => 'mod']], + Type::BIGFLOAT => ['BigFloat', ['+' => 'add', '-' => 'sub', '*' => 'mul', '/' => 'div']], }; $method = $opMap[$binaryOp] ?? null; @@ -595,9 +597,9 @@ trait AssignOpTrait // For bitwise shifts, the right operand is a shift amount (Int), not BigInt $isShift = ($binaryOp === '<<' || $binaryOp === '>>'); $convertedRight = match ($leftType) { - self::TYPE_BIGINT => $isShift ? $rightExpr : $this->convertBigIntExpr($rightExpr, $rightType), - self::TYPE_DECIMAL => $this->convertDecimalExpr($rightExpr, $rightType, $rightNode), - self::TYPE_BIGFLOAT => $this->convertBigFloatExpr($rightExpr, $rightType), + Type::BIGINT => $isShift ? $rightExpr : $this->convertBigIntExpr($rightExpr, $rightType), + Type::DECIMAL => $this->convertDecimalExpr($rightExpr, $rightType, $rightNode), + Type::BIGFLOAT => $this->convertBigFloatExpr($rightExpr, $rightType), }; return 'php::' . $class . '::' . $method . '(' . $leftExpr . ', ' . $convertedRight . ')'; @@ -681,16 +683,16 @@ trait AssignOpTrait if ($this->isVarExpr($expr->var)) { if (!$this->hasVar($left)) { - $this->addLocalVar($left, self::TYPE_REF); + $this->addLocalVar($left, Type::REF); } else { $type = $this->getVarType($left); - if ($type !== self::TYPE_REF) { + if ($type !== Type::REF) { $this->fatalError($expr, 'Cannot assign reference to variable of type ' . $type); } } } - $tmpVar = $this->addTmpVar(self::TYPE_REF); + $tmpVar = $this->addTmpVar(Type::REF); $rightExpr = ''; if ($this->isVarExpr($expr->expr)) { @@ -778,7 +780,7 @@ trait AssignOpTrait $value = $this->parseExprAsValue($right); $tmp = $this->genTmpVarName(); - $this->addLocalVar($tmp, self::TYPE_VAR); + $this->addLocalVar($tmp, Type::VAR); if ($left->dim === null) { return $code . '((' . $tmp . ' = ' . $value . ', ' . $this->emitDynamicPropertyFetchAppendArray($left->var, $tmp, $propertyWriteTarget) . '), ' . $tmp . ')'; @@ -815,7 +817,7 @@ trait AssignOpTrait protected function getNormalAssignType(string $type): string { - return $type === self::TYPE_REF || $type === self::TYPE_VOID ? self::TYPE_VAR : $type; + return $type === Type::REF || $type === Type::VOID ? Type::VAR : $type; } } diff --git a/src/Parser/BinaryOpTrait.php b/src/Parser/BinaryOpTrait.php index bbbed7ef..03f0f6a9 100644 --- a/src/Parser/BinaryOpTrait.php +++ b/src/Parser/BinaryOpTrait.php @@ -8,6 +8,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use TypePhp\Generator\Symbol; use PhpParser\Node; use PhpParser\Node\Expr; @@ -31,18 +33,18 @@ trait BinaryOpTrait $leftType = $this->detectTypeOfExpr($left); $rightType = $this->detectTypeOfExpr($right); - if ($leftType === self::TYPE_BIGFLOAT || $rightType === self::TYPE_BIGFLOAT) { + if ($leftType === Type::BIGFLOAT || $rightType === Type::BIGFLOAT) { // BigFloat cannot implicitly mix with BigInt or Decimal — risk of precision loss - if ($leftType === self::TYPE_BIGINT || $rightType === self::TYPE_BIGINT) { + if ($leftType === Type::BIGINT || $rightType === Type::BIGINT) { $this->fatalError($left, 'Cannot mix BigFloat and BigInt implicitly. Use std::bigFloat() to convert explicitly.'); } - if ($leftType === self::TYPE_DECIMAL || $rightType === self::TYPE_DECIMAL) { + if ($leftType === Type::DECIMAL || $rightType === Type::DECIMAL) { $this->fatalError($left, 'Cannot mix BigFloat and Decimal implicitly. Use std::bigFloat() to convert explicitly.'); } - if ($leftType !== self::TYPE_BIGFLOAT) { + if ($leftType !== Type::BIGFLOAT) { $leftExpr = $this->convertBigFloatExpr($leftExpr, $leftType); } - if ($rightType !== self::TYPE_BIGFLOAT) { + if ($rightType !== Type::BIGFLOAT) { $rightExpr = $this->convertBigFloatExpr($rightExpr, $rightType); } $arithOpMap = ['+' => 'add', '-' => 'sub', '*' => 'mul', '/' => 'div']; @@ -56,15 +58,15 @@ trait BinaryOpTrait } } - if ($leftType === self::TYPE_DECIMAL || $rightType === self::TYPE_DECIMAL) { + if ($leftType === Type::DECIMAL || $rightType === Type::DECIMAL) { // BigInt and Decimal cannot implicitly mix — risk of precision loss - if ($leftType === self::TYPE_BIGINT || $rightType === self::TYPE_BIGINT) { + if ($leftType === Type::BIGINT || $rightType === Type::BIGINT) { $this->fatalError($left, 'Cannot mix BigInt and Decimal implicitly. Use std::decimal() or std::bigInt() to convert explicitly.'); } - if ($leftType !== self::TYPE_DECIMAL) { + if ($leftType !== Type::DECIMAL) { $leftExpr = $this->convertDecimalExpr($leftExpr, $leftType, $left); } - if ($rightType !== self::TYPE_DECIMAL) { + if ($rightType !== Type::DECIMAL) { $rightExpr = $this->convertDecimalExpr($rightExpr, $rightType, $right); } $arithOpMap = ['+' => 'add', '-' => 'sub', '*' => 'mul', '/' => 'div', '%' => 'mod']; @@ -78,24 +80,24 @@ trait BinaryOpTrait } } - if ($leftType === self::TYPE_BIGINT || $rightType === self::TYPE_BIGINT) { + if ($leftType === Type::BIGINT || $rightType === Type::BIGINT) { // Bitwise shifts: right operand is shift amount, must stay as Int if ($op === '<<' || $op === '>>') { - if ($leftType !== self::TYPE_BIGINT) { + if ($leftType !== Type::BIGINT) { $leftExpr = $this->convertBigIntExpr($leftExpr, $leftType); } - if ($rightType === self::TYPE_BIGINT) { + if ($rightType === Type::BIGINT) { $rightExpr = 'php::BigInt::toInt(' . $rightExpr . ')'; - } elseif ($rightType !== self::TYPE_INT) { - $rightExpr = $this->convertExprType($rightExpr, $rightType, self::TYPE_INT); + } elseif ($rightType !== Type::INT) { + $rightExpr = $this->convertExprType($rightExpr, $rightType, Type::INT); } $method = ($op === '<<') ? 'bitShiftLeft' : 'bitShiftRight'; return 'php::BigInt::' . $method . '(' . $leftExpr . ', ' . $rightExpr . ')'; } - if ($leftType !== self::TYPE_BIGINT) { + if ($leftType !== Type::BIGINT) { $leftExpr = $this->convertBigIntExpr($leftExpr, $leftType); } - if ($rightType !== self::TYPE_BIGINT) { + if ($rightType !== Type::BIGINT) { $rightExpr = $this->convertBigIntExpr($rightExpr, $rightType); } $arithOpMap = ['+' => 'add', '-' => 'sub', '*' => 'mul', '/' => 'div', '%' => 'mod', '&' => 'bitAnd', '|' => 'bitOr', '^' => 'bitXor']; @@ -110,7 +112,7 @@ trait BinaryOpTrait } // Any Big*-typed operand reaching here means no Big* block handled the operator - $bigTypes = [self::TYPE_BIGFLOAT, self::TYPE_DECIMAL, self::TYPE_BIGINT]; + $bigTypes = [Type::BIGFLOAT, Type::DECIMAL, Type::BIGINT]; if (in_array($leftType, $bigTypes, true) || in_array($rightType, $bigTypes, true)) { $this->fatalError($left, "Operator '{$op}' is not supported for Big* numeric types"); } @@ -118,15 +120,15 @@ trait BinaryOpTrait // Only promote between native types (Int ↔ Float). When one side is // php::Var, let the Variant operator handle type coercion so that // run-time PHP type-juggling rules are followed correctly. - if ($leftType === self::TYPE_FLOAT && $rightType === self::TYPE_INT) { - $rightExpr = $this->convertExprType($rightExpr, self::TYPE_FLOAT, $rightType); - } elseif ($rightType === self::TYPE_FLOAT && $leftType === self::TYPE_INT) { - $leftExpr = $this->convertExprType($leftExpr, $leftType, self::TYPE_FLOAT); + if ($leftType === Type::FLOAT && $rightType === Type::INT) { + $rightExpr = $this->convertExprType($rightExpr, Type::FLOAT, $rightType); + } elseif ($rightType === Type::FLOAT && $leftType === Type::INT) { + $leftExpr = $this->convertExprType($leftExpr, $leftType, Type::FLOAT); } $this->guardLiteralDivisionByZero($right, $op); - if ($op === '%' and !($leftType === self::TYPE_INT and $rightType === self::TYPE_INT)) { + if ($op === '%' and !($leftType === Type::INT and $rightType === Type::INT)) { return 'php::fn::mod(' . $leftExpr . ', ' . $rightExpr . ')'; } @@ -191,7 +193,7 @@ trait BinaryOpTrait { if ($expr instanceof Expr\BinaryOp) { $type = $this->detectTypeOfExpr($expr); - return in_array($type, [self::TYPE_BIGINT, self::TYPE_DECIMAL, self::TYPE_BIGFLOAT], true) ? $type : self::TYPE_VAR; + return in_array($type, [Type::BIGINT, Type::DECIMAL, Type::BIGFLOAT], true) ? $type : Type::VAR; } if ( @@ -200,7 +202,7 @@ trait BinaryOpTrait || $expr instanceof Expr\StaticCall ) { $type = $this->detectTypeOfExpr($expr); - return in_array($type, [self::TYPE_BIGINT, self::TYPE_DECIMAL, self::TYPE_BIGFLOAT], true) ? $type : self::TYPE_VAR; + return in_array($type, [Type::BIGINT, Type::DECIMAL, Type::BIGFLOAT], true) ? $type : Type::VAR; } if ($expr instanceof Expr\PropertyFetch) { @@ -215,7 +217,7 @@ trait BinaryOpTrait return $def->type; } } - return self::TYPE_VAR; + return Type::VAR; } if ($expr instanceof Expr\StaticPropertyFetch) { @@ -223,11 +225,11 @@ trait BinaryOpTrait if ($def && $this->isNativePropertyTypedValue($expr)) { return $def->type; } - return self::TYPE_VAR; + return Type::VAR; } if ($expr instanceof Expr\ArrayDimFetch) { - return self::TYPE_VAR; + return Type::VAR; } $type = $this->detectTypeOfExpr($expr); @@ -305,11 +307,11 @@ trait BinaryOpTrait $this->assertExprCanBeUsedAsValue($expr->left, 'binary operand'); $this->assertExprCanBeUsedAsValue($expr->right, 'binary operand'); $leftType = $this->detectTypeOfExpr($expr->left); - if ($leftType === self::TYPE_BIGINT) { + if ($leftType === Type::BIGINT) { $leftExpr = $this->parseOrderedOperand($expr->left, false); $rightExpr = $this->parseOrderedOperand($expr->right, false); $rightType = $this->detectTypeOfExpr($expr->right); - if ($rightType !== self::TYPE_BIGINT) { + if ($rightType !== Type::BIGINT) { $rightExpr = $this->convertBigIntExpr($rightExpr, $rightType); } return 'php::BigInt::pow(' . $leftExpr . ', ' . $rightExpr . ')'; @@ -376,7 +378,7 @@ trait BinaryOpTrait */ private function optimizeIdenticalOp(NodeAbstract $astLeft, NodeAbstract $astRight, string $cppLeft, string $cppRight): ?string { - $primitiveTypes = [self::TYPE_INT, self::TYPE_FLOAT, self::TYPE_BOOL]; + $primitiveTypes = [Type::INT, Type::FLOAT, Type::BOOL]; $leftType = $this->detectTypeOfExpr($astLeft); $rightType = $this->detectTypeOfExpr($astRight); @@ -431,7 +433,7 @@ trait BinaryOpTrait $code .= $this->getIndent() . 'if (' . $rightCondition . ') {'; $code .= $this->formatCapturedStmtLines($rightBeforeStmts); if ($rightAfterStmts) { - $rightTmpVar = $this->addTmpVar(self::TYPE_VAR); + $rightTmpVar = $this->addTmpVar(Type::VAR); $code .= $this->getIndent() . $rightTmpVar . ' = ' . $rightExpr . ';'; $code .= $this->formatCapturedStmtLines($rightAfterStmts); $rightExpr = $rightTmpVar; @@ -470,35 +472,35 @@ trait BinaryOpTrait $leftType = $this->detectTypeOfExpr($expr->left); $rightType = $this->detectTypeOfExpr($expr->right); - if ($leftType === self::TYPE_BIGFLOAT || $rightType === self::TYPE_BIGFLOAT) { + if ($leftType === Type::BIGFLOAT || $rightType === Type::BIGFLOAT) { $leftExpr = $this->parseOrderedOperand($expr->left, false); $rightExpr = $this->parseOrderedOperand($expr->right, false); - if ($leftType !== self::TYPE_BIGFLOAT) { + if ($leftType !== Type::BIGFLOAT) { $leftExpr = $this->convertBigFloatExpr($leftExpr, $leftType); } - if ($rightType !== self::TYPE_BIGFLOAT) { + if ($rightType !== Type::BIGFLOAT) { $rightExpr = $this->convertBigFloatExpr($rightExpr, $rightType); } return 'php::BigFloat::cmp(' . $leftExpr . ', ' . $rightExpr . ')' . $suffix; } - if ($leftType === self::TYPE_BIGINT || $rightType === self::TYPE_BIGINT) { + if ($leftType === Type::BIGINT || $rightType === Type::BIGINT) { $leftExpr = $this->parseOrderedOperand($expr->left, false); $rightExpr = $this->parseOrderedOperand($expr->right, false); - if ($leftType !== self::TYPE_BIGINT) { + if ($leftType !== Type::BIGINT) { $leftExpr = $this->convertBigIntExpr($leftExpr, $leftType); } - if ($rightType !== self::TYPE_BIGINT) { + if ($rightType !== Type::BIGINT) { $rightExpr = $this->convertBigIntExpr($rightExpr, $rightType); } return 'php::BigInt::cmp(' . $leftExpr . ', ' . $rightExpr . ')' . $suffix; } - if ($leftType === self::TYPE_DECIMAL || $rightType === self::TYPE_DECIMAL) { + if ($leftType === Type::DECIMAL || $rightType === Type::DECIMAL) { $leftExpr = $this->parseOrderedOperand($expr->left, false); $rightExpr = $this->parseOrderedOperand($expr->right, false); - if ($leftType !== self::TYPE_DECIMAL) { + if ($leftType !== Type::DECIMAL) { $leftExpr = $this->convertDecimalExpr($leftExpr, $leftType, $expr->left); } - if ($rightType !== self::TYPE_DECIMAL) { + if ($rightType !== Type::DECIMAL) { $rightExpr = $this->convertDecimalExpr($rightExpr, $rightType, $expr->right); } return 'php::Decimal::cmp(' . $leftExpr . ', ' . $rightExpr . ')' . $suffix; diff --git a/src/Parser/ClassConstantFetchTrait.php b/src/Parser/ClassConstantFetchTrait.php index 4e37c0ef..5d16ecb5 100644 --- a/src/Parser/ClassConstantFetchTrait.php +++ b/src/Parser/ClassConstantFetchTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node\Expr; use PhpParser\NodeAbstract; use TypePhp\Generator\Symbol; @@ -88,7 +90,7 @@ trait ClassConstantFetchTrait { $this->assertExprCanBeUsedAsValue($expr, 'class constant target'); [$value, $beforeStmts, $afterStmts] = $this->parseExprWithCapturedStmts($expr); - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $this->appendCapturedStmtLinesToContext($beforeStmts); $this->context->beforeStmtLines[] = $tmpVar . ' = ' . $value . ';'; $this->appendCapturedStmtLinesToContext($afterStmts); diff --git a/src/Parser/ConstantExpressionTrait.php b/src/Parser/ConstantExpressionTrait.php index f9881e46..8f474652 100644 --- a/src/Parser/ConstantExpressionTrait.php +++ b/src/Parser/ConstantExpressionTrait.php @@ -8,6 +8,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\Node\Scalar\MagicConst; @@ -123,15 +125,15 @@ trait ConstantExpressionTrait return $this->getTypeFromZendType(gettype($this->internalConstants[$name])); } if (strcasecmp($name, 'true') === 0) { - return self::TYPE_BOOL; + return Type::BOOL; } if (strcasecmp($name, 'false') === 0) { - return self::TYPE_BOOL; + return Type::BOOL; } if ($name === 'NAN' or $name === 'INF') { - return self::TYPE_FLOAT; + return Type::FLOAT; } - return self::TYPE_VAR; + return Type::VAR; } protected function isInternalScalarConstant(string $name): bool diff --git a/src/Parser/ExceptionControlFlowTrait.php b/src/Parser/ExceptionControlFlowTrait.php index 3ccb1f16..561b623d 100644 --- a/src/Parser/ExceptionControlFlowTrait.php +++ b/src/Parser/ExceptionControlFlowTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\Node\Expr\Variable; @@ -26,13 +28,13 @@ trait ExceptionControlFlowTrait return 'php::throwException(' . $ex . ')'; } elseif ($this->isVarExpr($expr->expr)) { $ex = $this->parseIdentifier($expr->expr); - if ($type == self::TYPE_OBJECT) { + if ($type == Type::OBJECT) { return 'php::throwException(' . $ex . ')'; } } else { $ex = $this->parseExpr($expr->expr); } - if ($type != self::TYPE_VAR) { + if ($type != Type::VAR) { $this->fatalError($expr, 'Can only throw objects'); } return 'php::throwValue(' . $ex . ')'; @@ -55,7 +57,7 @@ trait ExceptionControlFlowTrait if ($catch->var) { $varName = $this->parseIdentifier($catch->var); if (!$this->hasVar($varName) && $this->stmtListUsesVariable($finally->stmts, $varName)) { - $this->addLocalVar($varName, self::TYPE_OBJECT); + $this->addLocalVar($varName, Type::OBJECT); } } } @@ -66,7 +68,7 @@ trait ExceptionControlFlowTrait $code .= $this->getIndent() . '}' . PHP_EOL; $exVar = $this->genTmpVarName(); - $this->addLocalVar($exVar, self::TYPE_VAR); + $this->addLocalVar($exVar, Type::VAR); $code .= 'catch(zend_object *_ex) {' . PHP_EOL; $code .= $this->getIndent() . $exVar . ' = php::catchException();' . PHP_EOL; @@ -99,7 +101,7 @@ trait ExceptionControlFlowTrait foreach ($stmts as $stmt) { if ($stmt instanceof Node\Stmt\Return_) { if ($stmt->expr) { - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $result[] = new Node\Stmt\Expression(new Expr\Assign(new Variable($tmpVar), $stmt->expr)); array_push($result, ...$this->cloneStmtList($finallyStmts)); $result[] = new Node\Stmt\Return_(new Variable($tmpVar)); @@ -191,7 +193,7 @@ trait ExceptionControlFlowTrait $types = $catch->types; $var = $catch->var ? $this->parseIdentifier($catch->var) : ''; if ($var !== '' && !$this->hasVar($var)) { - $this->addLocalVar($var, self::TYPE_OBJECT); + $this->addLocalVar($var, Type::OBJECT); } $code = $this->parseBeforeStmtLines() . PHP_EOL; diff --git a/src/Parser/ForeachTrait.php b/src/Parser/ForeachTrait.php index a35be6f6..5aee8ce7 100644 --- a/src/Parser/ForeachTrait.php +++ b/src/Parser/ForeachTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node\ArrayItem; use PhpParser\Node\Expr; use PhpParser\Node\Stmt\Foreach_; @@ -24,14 +26,14 @@ trait ForeachTrait $key = $item->key ? $this->parseArrayKey($item->key) : (string) $k; if ($item->value instanceof Expr\List_) { $nestedTmpVar = $this->genTmpVarName(); - $this->addLocalVar($nestedTmpVar, self::TYPE_VAR); + $this->addLocalVar($nestedTmpVar, Type::VAR); $code .= $this->getIndent() . ' ' . $nestedTmpVar . ' = ' . $listTmpVar . '.item(' . $key . ');' . PHP_EOL; $code .= $this->parseForeachItemAsList($nestedTmpVar, $item->value->items); continue; } $var = $this->parseWritableIdentifier($item->value); if ($this->isVarExpr($item->value) and !$this->hasVar($var)) { - $this->addLocalVar($var, self::TYPE_VAR); + $this->addLocalVar($var, Type::VAR); } $code .= $this->getIndent() . ' ' . $var . ' = ' . $listTmpVar . '.item(' . $key . ');' . PHP_EOL; } else { @@ -46,7 +48,7 @@ trait ForeachTrait return $this->parseStmts($node->stmts) . $this->genLoopEndFlagCheck(); } - protected function parseForeachKeyAssignment(Foreach_ $node, string $keyExpr, string $defaultType = self::TYPE_VAR): string + protected function parseForeachKeyAssignment(Foreach_ $node, string $keyExpr, string $defaultType = Type::VAR): string { if (!$node->keyVar) { return ''; @@ -72,7 +74,7 @@ trait ForeachTrait $this->fatalError($node, 'Foreach by reference cannot use list destructuring'); } $listTmpVar = $this->genTmpVarName(); - $this->addLocalVar($listTmpVar, self::TYPE_VAR); + $this->addLocalVar($listTmpVar, Type::VAR); return $this->getIndent() . ' ' . $listTmpVar . ' = ' . $valueExpr . ';' . PHP_EOL . $this->parseForeachItemAsList($listTmpVar, $node->valueVar->items); } @@ -92,8 +94,8 @@ trait ForeachTrait $valueVar = $this->parseIdentifier($node->valueVar); if ($node->byRef) { if (!$this->hasVar($valueVar)) { - $this->addLocalVar($valueVar, self::TYPE_REF); - } elseif ($this->getVarType($valueVar) !== self::TYPE_REF) { + $this->addLocalVar($valueVar, Type::REF); + } elseif ($this->getVarType($valueVar) !== Type::REF) { $this->fatalError($node, 'Cannot assign value to reference of type'); } return $this->getIndent() . ' ' . $valueVar . ' = ' . $valueRefExpr . ';' . PHP_EOL; @@ -130,7 +132,7 @@ trait ForeachTrait $name = $this->parseIdentifier($node->expr); if ($this->hasVar($name)) { $type = $this->getVarType($name); - if ($type === self::TYPE_OBJECT) { + if ($type === Type::OBJECT) { if ($node->byRef) { $this->fatalError($node, 'Cannot use & with foreach'); } @@ -148,9 +150,9 @@ trait ForeachTrait $iterableVar = $this->genTmpVarName(); $arrayVar = $this->genTmpVarName(); $objectVar = $this->genTmpVarName(); - $this->addLocalVar($iterableVar, self::TYPE_VAR); - $this->addLocalVar($arrayVar, self::TYPE_ARRAY); - $this->addLocalVar($objectVar, self::TYPE_OBJECT); + $this->addLocalVar($iterableVar, Type::VAR); + $this->addLocalVar($arrayVar, Type::ARRAY); + $this->addLocalVar($objectVar, Type::OBJECT); $code .= $iterableVar . ' = ' . $expr . ';' . PHP_EOL; $code .= 'if (' . $iterableVar . '.isArray()) {' . PHP_EOL; diff --git a/src/Parser/FunctionCallTrait.php b/src/Parser/FunctionCallTrait.php index 041710f4..f5c2f476 100644 --- a/src/Parser/FunctionCallTrait.php +++ b/src/Parser/FunctionCallTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\Node\Expr\CallLike; @@ -24,7 +26,7 @@ trait FunctionCallTrait [$leftExpr, $beforeStmts, $afterStmts] = $this->parseExprWithCapturedStmts($expr->left); $this->appendCapturedStmtLinesToContext($beforeStmts); - $value = $this->addTmpVar(self::TYPE_VAR); + $value = $this->addTmpVar(Type::VAR); $this->context->beforeStmtLines[] = $value . ' = ' . $leftExpr . ';'; $this->appendCapturedStmtLinesToContext($afterStmts); @@ -116,7 +118,7 @@ trait FunctionCallTrait $fn = $this->getFuncPtr($name); $this->context->beforeStmtLines[] = $this->formatCppLineComment('Func Call: ', $name . '()'); } else { - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $this->context->beforeStmtLines[] = $tmpVar . ' = ' . $this->parseExpr($expr->name) . ';'; $placeHolder = $fn = $tmpVar; $name = ''; diff --git a/src/Parser/LoopControlTrait.php b/src/Parser/LoopControlTrait.php index 6313496a..3a29ebbd 100644 --- a/src/Parser/LoopControlTrait.php +++ b/src/Parser/LoopControlTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node; trait LoopControlTrait @@ -56,7 +58,7 @@ trait LoopControlTrait foreach ($list_cond as [$condExpr, $beforeStmts, $afterStmts]) { $this->appendCapturedStmtLines($condCode, $beforeStmts); if ($afterStmts) { - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $condCode .= $this->getIndent() . $tmpVar . ' = ' . $condExpr . ';' . PHP_EOL; $this->appendCapturedStmtLines($condCode, $afterStmts); $condExpr = $tmpVar; @@ -115,7 +117,7 @@ trait LoopControlTrait $code .= 'while (true) {' . PHP_EOL; $this->appendCapturedStmtLines($code, $beforeStmts); if ($afterStmts) { - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $code .= $this->getIndent() . $tmpVar . ' = ' . $cond . ';' . PHP_EOL; $this->appendCapturedStmtLines($code, $afterStmts); $cond = $tmpVar; @@ -141,7 +143,7 @@ trait LoopControlTrait $condCode = '[&]() -> bool {'; $this->appendCapturedStmtLines($condCode, $beforeStmts); if ($afterStmts) { - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $condCode .= $this->getIndent() . $tmpVar . ' = ' . $cond . ';' . PHP_EOL; $this->appendCapturedStmtLines($condCode, $afterStmts); $cond = $tmpVar; diff --git a/src/Parser/MethodCallTrait.php b/src/Parser/MethodCallTrait.php index b84f73fc..3d78019e 100644 --- a/src/Parser/MethodCallTrait.php +++ b/src/Parser/MethodCallTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Modifiers; use PhpParser\Node; use PhpParser\Node\Expr; @@ -166,9 +168,9 @@ trait MethodCallTrait protected function parseNativeMethodCall(string $object, string $nativeFunc, array $args): string { - if ($this->getVarType($object) != self::TYPE_OBJECT) { + if ($this->getVarType($object) != Type::OBJECT) { $tmpVar = $this->genTmpVarName(); - $this->context->beforeStmtLines[] = self::TYPE_OBJECT . ' ' . $tmpVar . ' = ' . $object . ';'; + $this->context->beforeStmtLines[] = Type::OBJECT . ' ' . $tmpVar . ' = ' . $object . ';'; $object = $tmpVar; } if (count($args) === 0) { @@ -181,35 +183,35 @@ trait MethodCallTrait { $func = strtolower($this->parseIdentifier($expr->name)); $type = match ($func) { - 'int' => self::TYPE_INT, - 'float' => self::TYPE_FLOAT, - 'bool' => self::TYPE_BOOL, - 'bigint' => self::TYPE_BIGINT, - 'decimal' => self::TYPE_DECIMAL, - 'bigfloat' => self::TYPE_BIGFLOAT, + 'int' => Type::INT, + 'float' => Type::FLOAT, + 'bool' => Type::BOOL, + 'bigint' => Type::BIGINT, + 'decimal' => Type::DECIMAL, + 'bigfloat' => Type::BIGFLOAT, default => '', }; if ($type) { $expr->setAttribute('nativeType', $type); $valueExpr = $this->parseExpr($expr->args[0]->value); - if (in_array($type, [self::TYPE_INT, self::TYPE_FLOAT, self::TYPE_BOOL])) { + if (in_array($type, [Type::INT, Type::FLOAT, Type::BOOL])) { return $this->convertExprFromType($type, $valueExpr); } $argType = $this->detectTypeOfExpr($expr->args[0]->value); if ($argType === $type) { return $valueExpr; } - if ($type === self::TYPE_BIGINT) { - if ($argType === self::TYPE_FLOAT) { + if ($type === Type::BIGINT) { + if ($argType === Type::FLOAT) { $this->fatalError($expr, 'Cannot construct BigInt from float, use string or int instead'); } - if ($argType === self::TYPE_INT) { + if ($argType === Type::INT) { return 'php::toBigInt(' . $valueExpr . ')'; } return 'php::BigInt::newInstance(' . $valueExpr . ')'; } - if ($type === self::TYPE_DECIMAL) { - if ($argType === self::TYPE_FLOAT) { + if ($type === Type::DECIMAL) { + if ($argType === Type::FLOAT) { $argNode = $expr->args[0]->value; if ($argNode instanceof Node\Scalar\Float_) { $rawValue = $argNode->getAttribute('rawValue'); @@ -218,16 +220,16 @@ trait MethodCallTrait } $this->fatalError($expr, 'Cannot construct Decimal from float variable, use string or int instead'); } - if ($argType === self::TYPE_INT) { + if ($argType === Type::INT) { return 'php::toDecimal(' . $valueExpr . ')'; } return 'php::Decimal::newInstance(' . $valueExpr . ')'; } - if ($type === self::TYPE_BIGFLOAT) { - if ($argType === self::TYPE_INT) { + if ($type === Type::BIGFLOAT) { + if ($argType === Type::INT) { return 'php::toBigFloat(' . $valueExpr . ')'; } - if ($argType === self::TYPE_FLOAT) { + if ($argType === Type::FLOAT) { return 'php::toBigFloat(' . $valueExpr . ')'; } return 'php::BigFloat::newInstance(' . $valueExpr . ')'; @@ -310,8 +312,8 @@ trait MethodCallTrait if ($this->isNamedMethod($expr->name)) { $methodName = $expr->name->toString(); $receiverType = $this->isVarExpr($expr->var) ? $this->getVarType($object) : $this->detectTypeOfExpr($expr->var); - if ($receiverType === self::TYPE_VOID) { - $receiverType = self::TYPE_VAR; + if ($receiverType === Type::VOID) { + $receiverType = Type::VAR; } // to* builtins if (isset(self::KEYWORD_METHOD_MAP[$methodName])) { @@ -337,12 +339,12 @@ trait MethodCallTrait if ($this->isVarExpr($expr->var) and $this->isNamedMethod($expr->name)) { $type = $this->getVarType($object); // 引用参数允许方法调用:有class信息走原生调用,无class信息走动态调用 - if (!$this->checkArgType($type, self::TYPE_OBJECT) and $type !== self::TYPE_REF) { + if (!$this->checkArgType($type, Type::OBJECT) and $type !== Type::REF) { $methodName = $expr->name->toString(); // 非对象类型可使用内置方法 $fn = $this->findUniversalMethodAnyType($type, $methodName); if ($fn) { - if ($type === self::TYPE_STREAM) { + if ($type === Type::STREAM) { return $this->genStreamNullGuard($expr, $object, $methodName, $fn); } return $this->parseUniversalMethodCall($expr, $object, $methodName, $fn); @@ -384,10 +386,10 @@ trait MethodCallTrait // 表达式返回值也可使用内置方法:fn()->method(), $obj->fn()->method(), Foo::fn()->method(), $obj->prop->method() if (!$this->isVarExpr($expr->var) and $this->isNamedMethod($expr->name)) { $type = $this->detectTypeOfExpr($expr->var); - if ($type === self::TYPE_VOID) { - $type = self::TYPE_VAR; + if ($type === Type::VOID) { + $type = Type::VAR; } - if ($type !== self::TYPE_VAR && !$this->checkArgType($type, self::TYPE_OBJECT)) { + if ($type !== Type::VAR && !$this->checkArgType($type, Type::OBJECT)) { $methodName = $expr->name->toString(); $fn = $this->findUniversalMethodAnyType($type, $methodName); if ($fn) { @@ -397,7 +399,7 @@ trait MethodCallTrait if ($fn['handler'] === 'direct_method') { $receiver = $this->wrapUniversalReceiver($type, $object); } - if ($type === self::TYPE_STREAM) { + if ($type === Type::STREAM) { return $this->genStreamNullGuard($expr, $receiver, $methodName, $fn); } return $this->parseUniversalMethodCall($expr, $receiver, $methodName, $fn, false); @@ -458,7 +460,7 @@ trait MethodCallTrait $class = $this->getObjectType($var); goto _do_call; } - if ($this->getVarType($var) == self::TYPE_OBJECT) { + if ($this->getVarType($var) == Type::OBJECT) { $fn = 'php::concat({' . $var . '.getClassName(), "::", ' . $this->identifierToStr($expr->name) . '})'; } else { $fn = 'php::concat({' . $this->identifierToStr($expr->class) . ', "::", ' . $this->identifierToStr($expr->name) . '})'; diff --git a/src/Parser/NullsafeAccessTrait.php b/src/Parser/NullsafeAccessTrait.php index e98c4590..95e20567 100644 --- a/src/Parser/NullsafeAccessTrait.php +++ b/src/Parser/NullsafeAccessTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node\Expr; use PhpParser\NodeAbstract; @@ -59,11 +61,11 @@ trait NullsafeAccessTrait $this->errorUndefinedVariable($expr); } $type = $this->getVarType($object); - if ($type === self::TYPE_OBJECT) { + if ($type === Type::OBJECT) { break; } } - $object = $this->addTmpVar(self::TYPE_OBJECT); + $object = $this->addTmpVar(Type::OBJECT); $this->context->beforeStmtLines[] = $this->getIndent() . $object . ' = ' . $this->parseIdentifier($expr) . ';'; break; } @@ -74,10 +76,10 @@ trait NullsafeAccessTrait $last = array_key_last($list); $tmpFn = $this->genTmpVarName(); - $code = $comment . PHP_EOL . 'auto ' . $tmpFn . ' = [&]() -> ' . self::TYPE_VAR . '{' . PHP_EOL; + $code = $comment . PHP_EOL . 'auto ' . $tmpFn . ' = [&]() -> ' . Type::VAR . '{' . PHP_EOL; foreach ($list as $key => $item) { - $tmpVar = $this->addTmpVar($key !== $last ? self::TYPE_OBJECT : self::TYPE_VAR); + $tmpVar = $this->addTmpVar($key !== $last ? Type::OBJECT : Type::VAR); if ($item[3]) { $code .= "if ({$object}.isNull()) { return " . self::VALUE_NULL . '; }'; } @@ -151,7 +153,7 @@ trait NullsafeAccessTrait $this->detectClassOfExpr($baseExpr), $properties, $scope, - self::TYPE_OBJECT, + Type::OBJECT, ); foreach ($results as $index => $result) { $this->applyNativePropertyAccessResult($properties[$index]['node'], $result); diff --git a/src/Parser/PropertyAccessTrait.php b/src/Parser/PropertyAccessTrait.php index eabce74f..94165d92 100644 --- a/src/Parser/PropertyAccessTrait.php +++ b/src/Parser/PropertyAccessTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node; use PhpParser\Node\Expr; use PhpParser\NodeAbstract; @@ -286,7 +288,7 @@ trait PropertyAccessTrait $this->registerStaticPropertyRef($refVar, $class, $nativeProp, $info); if ($info['kind'] === 'zval') { - $helper = $def->type === self::TYPE_FLOAT ? 'typephp_static_float_ref' : 'typephp_static_int_ref'; + $helper = $def->type === Type::FLOAT ? 'typephp_static_float_ref' : 'typephp_static_int_ref'; return $helper . '(' . $refVar . ')'; } @@ -329,8 +331,8 @@ trait PropertyAccessTrait $classValue = $this->getDynamicStaticClassValue($expr->class); $propertyValue = $this->identifierToStr($expr->name, literal: true); - $classVar = $this->addTmpVar(self::TYPE_VAR); - $propertyVar = $this->addTmpVar(self::TYPE_VAR); + $classVar = $this->addTmpVar(Type::VAR); + $propertyVar = $this->addTmpVar(Type::VAR); $this->context->beforeStmtLines[] = $classVar . ' = ' . $classValue . ';'; $this->context->beforeStmtLines[] = $propertyVar . ' = ' . $propertyValue . ';'; @@ -456,7 +458,7 @@ trait PropertyAccessTrait // Untyped properties retain normal PHP mixed semantics: assigning // null is valid. Only an explicitly typed non-nullable property // can be rejected at compile time. - if ($def->type !== self::TYPE_VAR && !$def->nullable) { + if ($def->type !== Type::VAR && !$def->nullable) { $typeStr = $this->getObjectPropertyTypeCheckTypeString($def); $this->fatalError( $left, @@ -467,7 +469,7 @@ trait PropertyAccessTrait } $rightType = $this->detectTypeOfExpr($right); - if ($this->isFixedObjectProp($def) && $rightType !== self::TYPE_VAR) { + if ($this->isFixedObjectProp($def) && $rightType !== Type::VAR) { if (!$this->canAssignStaticTypeToObjectProperty($def, $rightType)) { $this->fatalError( $left, @@ -479,11 +481,11 @@ trait PropertyAccessTrait return; } - if ($def->type !== self::TYPE_OBJECT) { + if ($def->type !== Type::OBJECT) { return; } - if ($rightType !== self::TYPE_VAR && $rightType !== self::TYPE_OBJECT) { + if ($rightType !== Type::VAR && $rightType !== Type::OBJECT) { $this->fatalError( $left, "Cannot assign value of type `{$rightType}` to {$label} `{$propName}` of type `{$def->type}`" @@ -532,16 +534,16 @@ trait PropertyAccessTrait 'property assignment' ); } - if ($compositeRelation === self::COMPOSITE_TYPE_MATCH && $rightType !== self::TYPE_VAR) { + if ($compositeRelation === self::COMPOSITE_TYPE_MATCH && $rightType !== Type::VAR) { // A statically known member of the composite type needs no // Variant runtime guard on this property write. return $rightExpr; } - if ($rightType !== self::TYPE_VAR && $this->canAssignStaticTypeToObjectProperty($def, $rightType)) { + if ($rightType !== Type::VAR && $this->canAssignStaticTypeToObjectProperty($def, $rightType)) { return $rightExpr; } - if ($rightType === self::TYPE_VAR && ($helper = $this->getNativeScalarPropertyTypeCheckHelper($def)) !== null) { + if ($rightType === Type::VAR && ($helper = $this->getNativeScalarPropertyTypeCheckHelper($def)) !== null) { return $helper . '(' . $rightExpr . ', ' . $this->genCharPtr($this->getObjectPropertyTypeCheckDisplayName($left)) . ')'; } @@ -550,7 +552,7 @@ trait PropertyAccessTrait return $rightExpr; } - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $conditions = []; foreach ($typeCheck as $entry) { $cond = $this->genSingleTypeCondition($tmpVar, $entry); @@ -577,7 +579,7 @@ trait PropertyAccessTrait ? 'if (' . $tmpVar . '.isInt()) { ' . $tmpVar . ' = php::toFloat(' . $tmpVar . '); } ' : ''; - return '([&]() -> ' . self::TYPE_VAR . ' { ' + return '([&]() -> ' . Type::VAR . ' { ' . $tmpVar . ' = ' . $rightExpr . '; ' . $coercion . 'if (UNEXPECTED(!(' . implode(' || ', $conditions) . '))) { ' @@ -616,11 +618,11 @@ trait PropertyAccessTrait private function usesPhpStylePropertyAssignTypeError(PropertyDef $def): bool { return empty($def->typeCheck) && $def->class === '' && in_array($def->type, [ - self::TYPE_INT, - self::TYPE_FLOAT, - self::TYPE_BOOL, - self::TYPE_STR, - self::TYPE_ARRAY, + Type::INT, + Type::FLOAT, + Type::BOOL, + Type::STR, + Type::ARRAY, ], true); } @@ -631,9 +633,9 @@ trait PropertyAccessTrait } return match ($def->type) { - self::TYPE_INT => 'php::toIntExact', - self::TYPE_FLOAT => 'php::toFloatExact', - self::TYPE_BOOL => 'php::toBoolExact', + Type::INT => 'php::toIntExact', + Type::FLOAT => 'php::toFloatExact', + Type::BOOL => 'php::toBoolExact', default => null, }; } @@ -641,7 +643,7 @@ trait PropertyAccessTrait protected function canAssignStaticTypeToObjectProperty(PropertyDef $def, string $rightType): bool { return match ($def->type) { - self::TYPE_FLOAT => $rightType === self::TYPE_FLOAT || $rightType === self::TYPE_INT, + Type::FLOAT => $rightType === Type::FLOAT || $rightType === Type::INT, default => $rightType === $def->type, }; } @@ -649,12 +651,12 @@ trait PropertyAccessTrait protected function getPropertyAssignmentTypeName(string $type): string { return match ($type) { - self::TYPE_INT => 'int', - self::TYPE_FLOAT => 'float', - self::TYPE_BOOL => 'bool', - self::TYPE_STR => 'string', - self::TYPE_ARRAY => 'array', - self::TYPE_OBJECT => 'object', + Type::INT => 'int', + Type::FLOAT => 'float', + Type::BOOL => 'bool', + Type::STR => 'string', + Type::ARRAY => 'array', + Type::OBJECT => 'object', default => 'value', }; } @@ -692,7 +694,7 @@ trait PropertyAccessTrait // properties, so PHP can represent their uninitialized // state after unset(). Keep that behavior instead of // restoring a fixed default value. - if ($this->isFixedObjectProp($def) && $def->type !== self::TYPE_OBJECT) { + if ($this->isFixedObjectProp($def) && $def->type !== Type::OBJECT) { $restoreDefault = $this->getFixedObjectPropDefaultValue($def); if ($restoreDefault === null) { $this->fatalError($var, "Cannot unset object property `{$this->parseIdentifier($var->name)}` of fixed type `{$def->type}` without default value"); @@ -885,11 +887,11 @@ trait PropertyAccessTrait PropertyDef $def, string $getter, ): ?string { - if ($this->isPropertyFetchUpdate($expr) && !in_array($def->type, [self::TYPE_INT, self::TYPE_FLOAT], true)) { + if ($this->isPropertyFetchUpdate($expr) && !in_array($def->type, [Type::INT, Type::FLOAT], true)) { return null; } - if ($def->type === self::TYPE_BOOL) { + if ($def->type === Type::BOOL) { $this->setNativePropertyValueSource($expr, self::NATIVE_PROPERTY_VALUE_DYNAMIC); return $this->convertBoolExpr($getter); } diff --git a/src/Parser/SelectionExpressionTrait.php b/src/Parser/SelectionExpressionTrait.php index 359e0d49..4f7cd90a 100644 --- a/src/Parser/SelectionExpressionTrait.php +++ b/src/Parser/SelectionExpressionTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node\Expr; use PhpParser\NodeAbstract; @@ -44,10 +46,10 @@ trait SelectionExpressionTrait $else = 'php::Var(' . $else . ')'; } if ($hasBranchStmts) { - $code = '[&]() -> ' . self::TYPE_VAR . '{'; + $code = '[&]() -> ' . Type::VAR . '{'; $code .= $this->formatCapturedStmtLines($condBeforeStmts); if ($condAfterStmts) { - $condTmpVar = $this->addTmpVar(self::TYPE_VAR); + $condTmpVar = $this->addTmpVar(Type::VAR); $code .= $this->getIndent() . "{$condTmpVar} = {$cond};"; $code .= $this->formatCapturedStmtLines($condAfterStmts); $cond = $condTmpVar; @@ -67,7 +69,7 @@ trait SelectionExpressionTrait { $code = $this->formatCapturedStmtLines($beforeStmts); if ($afterStmts) { - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $code .= $this->getIndent() . "{$tmpVar} = {$value};"; $code .= $this->formatCapturedStmtLines($afterStmts); $code .= $this->getIndent() . 'return ' . $tmpVar . ';'; @@ -86,12 +88,12 @@ trait SelectionExpressionTrait $this->errorUndefinedVariable($expr->cond); } } else { - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $this->context->beforeStmtLines[] = $tmpVar . ' = ' . $var . ';'; $var = $tmpVar; } - $code = '[&]() -> ' . self::TYPE_VAR . '{'; + $code = '[&]() -> ' . Type::VAR . '{'; $default = null; foreach ($expr->arms as $arm) { if ($arm->conds === null) { @@ -109,7 +111,7 @@ trait SelectionExpressionTrait $code .= $this->getIndent() . 'if (!' . $matched . ') {'; $code .= $this->formatCapturedStmtLines($beforeStmts); if ($afterStmts) { - $condTmpVar = $this->addTmpVar(self::TYPE_VAR); + $condTmpVar = $this->addTmpVar(Type::VAR); $code .= $this->getIndent() . "{$condTmpVar} = {$condValue};"; $code .= $this->formatCapturedStmtLines($afterStmts); $condValue = $condTmpVar; @@ -140,7 +142,7 @@ trait SelectionExpressionTrait [$value, $beforeStmts, $afterStmts] = $this->parseExprWithCapturedStmts($body); $code = $this->formatCapturedStmtLines($beforeStmts); if ($afterStmts) { - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $code .= $this->getIndent() . "{$tmpVar} = {$value};"; $code .= $this->formatCapturedStmtLines($afterStmts); $code .= $this->getIndent() . 'return ' . $tmpVar . ';'; @@ -175,7 +177,7 @@ trait SelectionExpressionTrait $this->context->afterStmtLines = array_slice($this->context->afterStmtLines, 0, $rightAfterStmtCount); $this->checkVarMustExist($right, $rightExpr); - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); if ($rightBeforeStmts || $rightAfterStmts) { $code = $this->formatCppLineComment('Expr: ', $this->printer->prettyPrintExpr($expr)) . PHP_EOL . 'if (' . $condExpr . ') {' . PHP_EOL . @@ -185,7 +187,7 @@ trait SelectionExpressionTrait $code .= $this->getIndent() . implode(PHP_EOL . $this->getIndent(), $rightBeforeStmts) . PHP_EOL; } if ($rightAfterStmts) { - $rightTmpVar = $this->addTmpVar(self::TYPE_VAR); + $rightTmpVar = $this->addTmpVar(Type::VAR); $code .= $this->getIndent() . $rightTmpVar . ' = ' . $rightExpr . ';' . PHP_EOL; $code .= $this->getIndent() . implode(PHP_EOL . $this->getIndent(), $rightAfterStmts) . PHP_EOL; $code .= $this->getIndent() . $tmpVar . ' = ' . $rightTmpVar . ';' . PHP_EOL; diff --git a/src/Parser/StdContainerTrait.php b/src/Parser/StdContainerTrait.php index 522ab04a..a0ad918e 100644 --- a/src/Parser/StdContainerTrait.php +++ b/src/Parser/StdContainerTrait.php @@ -8,6 +8,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use TypePhp\Generator\Symbol; use PhpParser\Node\Expr; use PhpParser\Node\Expr\StaticCall; @@ -26,31 +28,31 @@ trait StdContainerTrait protected function isStdContainerType(string $type): bool { return in_array($type, [ - self::TYPE_STD_ARRAY, - self::TYPE_STD_VECTOR, - self::TYPE_STD_MAP, - self::TYPE_STD_ORDERED_MAP, + Type::STD_ARRAY, + Type::STD_VECTOR, + Type::STD_MAP, + Type::STD_ORDERED_MAP, ], true); } protected function isStdArray(string $var): bool { - return $this->hasLocalVar($var) and $this->getVarType($var) === self::TYPE_STD_ARRAY; + return $this->hasLocalVar($var) and $this->getVarType($var) === Type::STD_ARRAY; } protected function isStdVector(string $var): bool { - return $this->hasLocalVar($var) and $this->getVarType($var) === self::TYPE_STD_VECTOR; + return $this->hasLocalVar($var) and $this->getVarType($var) === Type::STD_VECTOR; } protected function isStdMap(string $var): bool { - return $this->hasLocalVar($var) and $this->getVarType($var) === self::TYPE_STD_MAP; + return $this->hasLocalVar($var) and $this->getVarType($var) === Type::STD_MAP; } protected function isStdOrderedMap(string $var): bool { - return $this->hasLocalVar($var) and $this->getVarType($var) === self::TYPE_STD_ORDERED_MAP; + return $this->hasLocalVar($var) and $this->getVarType($var) === Type::STD_ORDERED_MAP; } protected function getStdTypeKey(array $info): string @@ -84,7 +86,7 @@ trait StdContainerTrait protected function getStdContainerKeyType(string $var): string { if ($this->isStdVector($var) or $this->isStdArray($var)) { - return self::TYPE_INT; + return Type::INT; } return $this->getStdContainerVarInfo($var)['keyType']; } @@ -93,9 +95,9 @@ trait StdContainerTrait { $info = $this->getStdContainerVarInfo($var); if ($this->isStdArray($var)) { - return count($info['sizes']) > 1 ? self::TYPE_ARRAY : $info['type']; + return count($info['sizes']) > 1 ? Type::ARRAY : $info['type']; } - if ($info['type'] === self::TYPE_OBJECT and $info['class']) { + if ($info['type'] === Type::OBJECT and $info['class']) { $this->addObject($valueVar, $info['class']); } else { unset($this->context->objects[$valueVar]); @@ -105,7 +107,7 @@ trait StdContainerTrait protected function getStdArrayDecl(string $type, array $sizes): string { - $decl = str_repeat(self::TYPE_STD_ARRAY . '<', count($sizes)); + $decl = str_repeat(Type::STD_ARRAY . '<', count($sizes)); $decl .= $this->getStdContainerElementType($type); for ($i = count($sizes) - 1; $i >= 0; $i--) { $decl .= ', ' . $sizes[$i] . '>'; @@ -116,8 +118,8 @@ trait StdContainerTrait protected function getStdValueTypeBytes(string $type): int { return match ($type) { - self::TYPE_BOOL => 1, - self::TYPE_INT, self::TYPE_FLOAT => 8, + Type::BOOL => 1, + Type::INT, Type::FLOAT => 8, default => 16, }; } @@ -451,7 +453,7 @@ trait StdContainerTrait protected function convertStdContainerKey(array $info, string $index): string { - if ($info['keyType'] === self::TYPE_STR) { + if ($info['keyType'] === Type::STR) { return $this->convertStringExpr($index); } return $this->convertIntExpr($index); @@ -460,7 +462,7 @@ trait StdContainerTrait protected function getStdContainerElementType(string $type): string { return match ($type) { - self::TYPE_BIGINT, self::TYPE_BIGFLOAT, self::TYPE_DECIMAL, self::TYPE_STREAM, self::TYPE_BOX => self::TYPE_VAR, + Type::BIGINT, Type::BIGFLOAT, Type::DECIMAL, Type::STREAM, Type::BOX => Type::VAR, default => $type, }; } @@ -474,12 +476,12 @@ trait StdContainerTrait $this->fatalError($expr, "An incorrect `{$owner}` definition"); } return match (strtolower($expr->name->name)) { - 'type_int' => self::TYPE_INT, - 'type_float' => self::TYPE_FLOAT, - 'type_bool' => self::TYPE_BOOL, - 'type_bigint' => self::TYPE_BIGINT, - 'type_bigfloat' => self::TYPE_BIGFLOAT, - 'type_decimal' => self::TYPE_DECIMAL, + 'type_int' => Type::INT, + 'type_float' => Type::FLOAT, + 'type_bool' => Type::BOOL, + 'type_bigint' => Type::BIGINT, + 'type_bigfloat' => Type::BIGFLOAT, + 'type_decimal' => Type::DECIMAL, default => $this->fatalError($expr, "An incorrect `{$owner}` definition"), }; } @@ -499,12 +501,12 @@ trait StdContainerTrait if ($className === 'complex_types') { return [ 'type' => match (strtolower($expr->name->name)) { - 'type_str', 'type_string' => self::TYPE_STR, - 'type_array' => self::TYPE_ARRAY, - 'type_object' => self::TYPE_OBJECT, - 'type_any', 'type_var', 'type_variant' => self::TYPE_VAR, - 'type_stream' => self::TYPE_STREAM, - 'type_box' => self::TYPE_BOX, + 'type_str', 'type_string' => Type::STR, + 'type_array' => Type::ARRAY, + 'type_object' => Type::OBJECT, + 'type_any', 'type_var', 'type_variant' => Type::VAR, + 'type_stream' => Type::STREAM, + 'type_box' => Type::BOX, default => $this->fatalError($expr, "An incorrect `{$owner}` definition"), }, 'class' => null, @@ -514,7 +516,7 @@ trait StdContainerTrait $this->fatalError($expr, "{$owner} class value only supports ClassName::class"); } $class = $this->parseStdClassValueType($expr, $owner); - return ['type' => self::TYPE_OBJECT, 'class' => $class]; + return ['type' => Type::OBJECT, 'class' => $class]; } protected function parseStdValueType(NodeAbstract $expr, string $owner): string @@ -550,7 +552,7 @@ trait StdContainerTrait $class = $info['class'] ?? null; if ($class === null) { $targetType = $info['type']; - if ($targetType === self::TYPE_BIGINT || $targetType === self::TYPE_BIGFLOAT || $targetType === self::TYPE_DECIMAL || $targetType === self::TYPE_STREAM || $targetType === self::TYPE_BOX) { + if ($targetType === Type::BIGINT || $targetType === Type::BIGFLOAT || $targetType === Type::DECIMAL || $targetType === Type::STREAM || $targetType === Type::BOX) { return $this->convertStdVarBackedExpr($targetType, $valueExpr, $expr); } return $this->convertExprFromType($targetType, $valueExpr); @@ -571,16 +573,16 @@ trait StdContainerTrait if ($sourceType === $targetType) { return $valueExpr; } - if ($targetType === self::TYPE_STREAM || $targetType === self::TYPE_BOX) { + if ($targetType === Type::STREAM || $targetType === Type::BOX) { return $valueExpr; } - if ($targetType === self::TYPE_BIGINT) { + if ($targetType === Type::BIGINT) { return $this->convertBigIntExpr($valueExpr, $sourceType); } - if ($targetType === self::TYPE_BIGFLOAT) { + if ($targetType === Type::BIGFLOAT) { return $this->convertBigFloatExpr($valueExpr, $sourceType); } - if ($targetType === self::TYPE_DECIMAL) { + if ($targetType === Type::DECIMAL) { return $this->convertDecimalExpr($valueExpr, $sourceType, $expr); } return $valueExpr; @@ -609,20 +611,20 @@ trait StdContainerTrait $fakeCall = new StaticCall($name, $method, $expr->args); if ($containerType === 'array') { - $this->addLocalVar($var, self::TYPE_STD_ARRAY); + $this->addLocalVar($var, Type::STD_ARRAY); $this->parseStdArray($var, $fakeCall); $this->context->stdArrays[$var]['boxExpr'] = $sourceVar; return '// StdContainer<' . $this->context->stdArrays[$var]['decl'] . '>(' . $sourceVar . ')'; } if ($containerType === 'vector') { - $this->addLocalVar($var, self::TYPE_STD_VECTOR); + $this->addLocalVar($var, Type::STD_VECTOR); $this->parseStdVector($var, $fakeCall); } elseif ($containerType === 'map') { - $this->addLocalVar($var, self::TYPE_STD_MAP); + $this->addLocalVar($var, Type::STD_MAP); $this->parseStdMap($var, $fakeCall); } else { - $this->addLocalVar($var, self::TYPE_STD_ORDERED_MAP); + $this->addLocalVar($var, Type::STD_ORDERED_MAP); $this->parseStdOrderedMap($var, $fakeCall); } $this->context->stdContainers[$var]['boxExpr'] = $sourceVar; @@ -637,10 +639,10 @@ trait StdContainerTrait $className = strtolower($expr->class->toString()); $constName = strtolower($expr->name->name); if ($className === 'native_types' && $constName === 'type_int') { - return self::TYPE_INT; + return Type::INT; } if ($className === 'complex_types' && in_array($constName, ['type_string', 'type_str'], true)) { - return self::TYPE_STR; + return Type::STR; } $this->fatalError($expr, "{$owner} key only supports native_types::type_int, complex_types::type_string or complex_types::type_str"); } @@ -710,7 +712,7 @@ trait StdContainerTrait } $size = $expr->args[1]->value->value; } - $decl = self::TYPE_STD_VECTOR . '<' . $this->getStdContainerElementType($type) . '>'; + $decl = Type::STD_VECTOR . '<' . $this->getStdContainerElementType($type) . '>'; $this->context->stdContainers[$var] = $this->addStdTypeId([ 'kind' => 'vector', 'decl' => $decl, @@ -723,12 +725,12 @@ trait StdContainerTrait protected function parseStdMap(string $var, Expr\StaticCall $expr): string { - return $this->parseStdMapBase($var, $expr, 'std::map', self::TYPE_STD_MAP, 'map'); + return $this->parseStdMapBase($var, $expr, 'std::map', Type::STD_MAP, 'map'); } protected function parseStdOrderedMap(string $var, Expr\StaticCall $expr): string { - return $this->parseStdMapBase($var, $expr, 'std::ordered_map', self::TYPE_STD_ORDERED_MAP, 'ordered_map'); + return $this->parseStdMapBase($var, $expr, 'std::ordered_map', Type::STD_ORDERED_MAP, 'ordered_map'); } private function parseStdMapBase(string $var, Expr\StaticCall $expr, string $funcName, string $containerType, string $kind): string diff --git a/src/Parser/SwitchTrait.php b/src/Parser/SwitchTrait.php index 5d2517e6..ca770119 100644 --- a/src/Parser/SwitchTrait.php +++ b/src/Parser/SwitchTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node; trait SwitchTrait @@ -30,7 +32,7 @@ trait SwitchTrait $localVars = $this->context->localVars; $code = $this->parseBeforeStmtLines() . PHP_EOL; - if ($type === self::TYPE_INT or $type === self::TYPE_BOOL) { + if ($type === Type::INT or $type === Type::BOOL) { $code .= 'do {' . PHP_EOL; $this->indentLevel++; $code .= $this->getIndent() . 'switch (' . $tmp_var . ') {' . PHP_EOL; @@ -118,7 +120,7 @@ trait SwitchTrait $code .= $this->getIndent() . 'if (!' . $switchMatched . ' && !' . $groupMatched . ') {' . PHP_EOL; $this->appendCapturedStmtLines($code, $caseBeforeStmts); if ($caseAfterStmts) { - $caseTmpVar = $this->addTmpVar(self::TYPE_VAR); + $caseTmpVar = $this->addTmpVar(Type::VAR); $code .= $this->getIndent() . $caseTmpVar . ' = ' . $caseCondExpr . ';' . PHP_EOL; $this->appendCapturedStmtLines($code, $caseAfterStmts); $caseCondExpr = $caseTmpVar; diff --git a/src/Parser/TypeConversionTrait.php b/src/Parser/TypeConversionTrait.php index 4632b336..6bed4424 100644 --- a/src/Parser/TypeConversionTrait.php +++ b/src/Parser/TypeConversionTrait.php @@ -8,6 +8,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node; use PhpParser\NodeAbstract; @@ -15,13 +17,13 @@ trait TypeConversionTrait { protected function convertExprToStringByType(string $expr, $type): string { - if ($type === self::TYPE_BIGINT) { + if ($type === Type::BIGINT) { return 'php::BigInt::toString(' . $expr . ')'; } - if ($type === self::TYPE_BIGFLOAT) { + if ($type === Type::BIGFLOAT) { return 'php::BigFloat::toString(' . $expr . ')'; } - if ($type === self::TYPE_DECIMAL) { + if ($type === Type::DECIMAL) { return 'php::Decimal::toString(' . $expr . ')'; } return $this->convertStringExpr($expr); @@ -47,7 +49,7 @@ trait TypeConversionTrait protected function convertDecimalExpr(string $expr, string $fromType = '', ?NodeAbstract $node = null): string { - if ($fromType === self::TYPE_FLOAT) { + if ($fromType === Type::FLOAT) { if ($node instanceof Node\Scalar\Float_) { $rawValue = $node->getAttribute('rawValue'); $clean = $rawValue !== null ? $this->stripNumericUnderscores($rawValue) : (string) $node->value; @@ -55,16 +57,16 @@ trait TypeConversionTrait } $this->fatalError($node, 'Cannot convert float expression to Decimal, use a literal value or string instead'); } - if ($fromType === self::TYPE_STR) { + if ($fromType === Type::STR) { if ($node instanceof Node\Scalar\String_) { return 'php::toDecimal(' . $this->getLiteralString($node->value) . ')'; } return 'php::toDecimal(php::toString(' . $expr . '))'; } - if ($fromType === self::TYPE_INT) { + if ($fromType === Type::INT) { return 'php::toDecimal(php::toString(' . $expr . '))'; } - if ($fromType === self::TYPE_BIGINT) { + if ($fromType === Type::BIGINT) { return 'php::toDecimal(php::BigInt::toString(' . $expr . '))'; } return $expr; @@ -72,13 +74,13 @@ trait TypeConversionTrait protected function convertBigIntExpr(string $expr, string $fromType = ''): string { - if ($fromType === self::TYPE_INT) { + if ($fromType === Type::INT) { return 'php::toBigInt(' . $expr . ')'; } - if ($fromType === self::TYPE_FLOAT) { + if ($fromType === Type::FLOAT) { $this->error('Cannot convert float to BigInt, use string or int instead'); } - if ($fromType === self::TYPE_STR) { + if ($fromType === Type::STR) { return 'php::toBigInt(php::toString(' . $expr . '))'; } return $expr; @@ -86,19 +88,19 @@ trait TypeConversionTrait protected function convertBigFloatExpr(string $expr, string $fromType = ''): string { - if ($fromType === self::TYPE_INT) { + if ($fromType === Type::INT) { return 'php::toBigFloat(' . $expr . ')'; } - if ($fromType === self::TYPE_FLOAT) { + if ($fromType === Type::FLOAT) { return 'php::toBigFloat(' . $expr . ')'; } - if ($fromType === self::TYPE_STR) { + if ($fromType === Type::STR) { return 'php::toBigFloat(php::toString(' . $expr . '))'; } - if ($fromType === self::TYPE_BIGINT) { + if ($fromType === Type::BIGINT) { return 'php::BigFloat::newInstance(php::BigInt::toString(' . $expr . '))'; } - if ($fromType === self::TYPE_DECIMAL) { + if ($fromType === Type::DECIMAL) { return 'php::BigFloat::newInstance(php::Decimal::toString(' . $expr . '))'; } return $expr; @@ -145,13 +147,13 @@ trait TypeConversionTrait protected function convertExprType(string $expr, $leftType, $rightType): string { - if ($leftType === self::TYPE_FLOAT or $rightType === self::TYPE_FLOAT) { + if ($leftType === Type::FLOAT or $rightType === Type::FLOAT) { return $this->convertFloatExpr($expr); } - if ($leftType === self::TYPE_INT or $rightType === self::TYPE_INT) { + if ($leftType === Type::INT or $rightType === Type::INT) { return $this->convertIntExpr($expr); } - if ($leftType === self::TYPE_BOOL or $rightType === self::TYPE_BOOL) { + if ($leftType === Type::BOOL or $rightType === Type::BOOL) { return $this->convertBoolExpr($expr); } @@ -160,33 +162,33 @@ trait TypeConversionTrait protected function getNativeType(string $type): string { - if ($type === self::TYPE_INT && $this->bigintTypes) { - return self::TYPE_BIGINT; + if ($type === Type::INT && $this->bigintTypes) { + return Type::BIGINT; } - if ($type === self::TYPE_FLOAT && $this->decimalTypes) { - return self::TYPE_DECIMAL; + if ($type === Type::FLOAT && $this->decimalTypes) { + return Type::DECIMAL; } - return $this->nativeTypes ? $type : self::TYPE_VAR; + return $this->nativeTypes ? $type : Type::VAR; } protected function convertExprFromType(string $type, string $expr): string { - if ($type === self::TYPE_FLOAT) { + if ($type === Type::FLOAT) { return $this->convertFloatExpr($expr); } - if ($type === self::TYPE_INT) { + if ($type === Type::INT) { return $this->convertIntExpr($expr); } - if ($type === self::TYPE_BOOL) { + if ($type === Type::BOOL) { return $this->convertBoolExpr($expr); } - if ($type === self::TYPE_STR) { + if ($type === Type::STR) { return $this->convertStringExpr($expr); } - if ($type === self::TYPE_ARRAY) { + if ($type === Type::ARRAY) { return $this->convertArrayExpr($expr); } - if ($type === self::TYPE_OBJECT) { + if ($type === Type::OBJECT) { return $this->convertObjectExpr($expr); } @@ -207,7 +209,7 @@ trait TypeConversionTrait $this->checkLeftValue($expr); $var = $this->parseIdentifier($expr); if ($this->isVarExpr($expr) and $this->isNativeTypeVar($var)) { - $this->context->localVars[$var] = self::TYPE_VAR; + $this->context->localVars[$var] = Type::VAR; } return $this->parseIdentifier($expr) . '.toReference()'; } diff --git a/src/Parser/TypeDetectionTrait.php b/src/Parser/TypeDetectionTrait.php index 2bc7d5ce..0e3762ca 100644 --- a/src/Parser/TypeDetectionTrait.php +++ b/src/Parser/TypeDetectionTrait.php @@ -8,6 +8,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use TypePhp\Resolver\Reflection; use PhpParser\Node; use PhpParser\Node\Expr; @@ -76,7 +78,7 @@ trait TypeDetectionTrait protected function isNativeType(string $type): bool { - return in_array($type, [self::TYPE_INT, self::TYPE_FLOAT, self::TYPE_BOOL]); + return in_array($type, [Type::INT, Type::FLOAT, Type::BOOL]); } protected function isNativeTypeVar(string $var): bool @@ -140,7 +142,7 @@ trait TypeDetectionTrait protected function isArrayVar($var): bool { - return $this->isVarExpr($var) and $this->hasVar($var->name) and $this->getVarType($var->name) === self::TYPE_ARRAY; + return $this->isVarExpr($var) and $this->hasVar($var->name) and $this->getVarType($var->name) === Type::ARRAY; } } diff --git a/src/Parser/UnaryExpressionTrait.php b/src/Parser/UnaryExpressionTrait.php index 5321bb8e..ab2f336d 100644 --- a/src/Parser/UnaryExpressionTrait.php +++ b/src/Parser/UnaryExpressionTrait.php @@ -8,6 +8,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use PhpParser\Node\Expr; trait UnaryExpressionTrait @@ -16,7 +18,7 @@ trait UnaryExpressionTrait { $type = $this->detectTypeOfExpr($expr->expr); $this->assertExprCanBeUsedAsValue($expr->expr, 'bitwise operand'); - if ($type === self::TYPE_BIGINT) { + if ($type === Type::BIGINT) { return 'php::BigInt::bitNot(' . $this->parseExpr($expr->expr) . ')'; } $var = $this->parseIdentifier($expr->expr); @@ -60,13 +62,13 @@ trait UnaryExpressionTrait { $type = $this->detectTypeOfExpr($expr->expr); $this->assertExprCanBeUsedAsValue($expr->expr, 'unary operand'); - if ($type === self::TYPE_BIGFLOAT) { + if ($type === Type::BIGFLOAT) { return 'php::BigFloat::neg(' . $this->parseExprAsValue($expr->expr) . ')'; } - if ($type === self::TYPE_BIGINT) { + if ($type === Type::BIGINT) { return 'php::BigInt::neg(' . $this->parseExprAsValue($expr->expr) . ')'; } - if ($type === self::TYPE_DECIMAL) { + if ($type === Type::DECIMAL) { return 'php::Decimal::neg(' . $this->parseExprAsValue($expr->expr) . ')'; } $code = $this->parseExprAsValue($expr->expr); diff --git a/src/Parser/UniversalMethodCall.php b/src/Parser/UniversalMethodCall.php index e7252a4d..cac59dda 100644 --- a/src/Parser/UniversalMethodCall.php +++ b/src/Parser/UniversalMethodCall.php @@ -2,6 +2,8 @@ namespace TypePhp\Parser; +use TypePhp\Type; + use TypePhp\CompilerBase; use TypePhp\Resolver\Reflection; @@ -12,314 +14,314 @@ use PhpParser\NodeAbstract; trait UniversalMethodCall { protected const array UNIVERSAL_METHODS = [ - CompilerBase::TYPE_INT => [ - 'add' => ['handler' => 'calc_op', 'op' => '+', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'sub' => ['handler' => 'calc_op', 'op' => '-', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'mul' => ['handler' => 'calc_op', 'op' => '*', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'div' => ['handler' => 'calc_op', 'op' => '/', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'mod' => ['handler' => 'calc_op', 'op' => '%', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'inc' => ['handler' => 'calc_inc', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 0, 'max_args' => 0], - 'dec' => ['handler' => 'calc_dec', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 0, 'max_args' => 0], + Type::INT => [ + 'add' => ['handler' => 'calc_op', 'op' => '+', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'sub' => ['handler' => 'calc_op', 'op' => '-', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'mul' => ['handler' => 'calc_op', 'op' => '*', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'div' => ['handler' => 'calc_op', 'op' => '/', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'mod' => ['handler' => 'calc_op', 'op' => '%', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'inc' => ['handler' => 'calc_inc', 'return_type' => Type::INT, 'min_args' => 0, 'max_args' => 0], + 'dec' => ['handler' => 'calc_dec', 'return_type' => Type::INT, 'min_args' => 0, 'max_args' => 0], // math - 'abs' => ['handler' => 'php_fn', 'fn' => 'abs', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 0, 'max_args' => 0], - 'ceil' => ['handler' => 'php_fn', 'fn' => 'ceil', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'floor' => ['handler' => 'php_fn', 'fn' => 'floor', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'round' => ['handler' => 'php_fn', 'fn' => 'round', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 2], - 'sqrt' => ['handler' => 'php_fn', 'fn' => 'sqrt', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'pow' => ['handler' => 'php_fn', 'fn' => 'pow', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 1], - 'log' => ['handler' => 'php_fn', 'fn' => 'log', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 1], - 'log10' => ['handler' => 'php_fn', 'fn' => 'log10', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'exp' => ['handler' => 'php_fn', 'fn' => 'exp', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'sin' => ['handler' => 'php_fn', 'fn' => 'sin', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'cos' => ['handler' => 'php_fn', 'fn' => 'cos', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'tan' => ['handler' => 'php_fn', 'fn' => 'tan', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'asin' => ['handler' => 'php_fn', 'fn' => 'asin', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'acos' => ['handler' => 'php_fn', 'fn' => 'acos', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'atan' => ['handler' => 'php_fn', 'fn' => 'atan', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'atan2' => ['handler' => 'php_fn', 'fn' => 'atan2', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], - 'deg2rad' => ['handler' => 'php_fn', 'fn' => 'deg2rad', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'rad2deg' => ['handler' => 'php_fn', 'fn' => 'rad2deg', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'max' => ['handler' => 'php_fn', 'fn' => 'max', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'min' => ['handler' => 'php_fn', 'fn' => 'min', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], + 'abs' => ['handler' => 'php_fn', 'fn' => 'abs', 'return_type' => Type::INT, 'min_args' => 0, 'max_args' => 0], + 'ceil' => ['handler' => 'php_fn', 'fn' => 'ceil', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'floor' => ['handler' => 'php_fn', 'fn' => 'floor', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'round' => ['handler' => 'php_fn', 'fn' => 'round', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 2], + 'sqrt' => ['handler' => 'php_fn', 'fn' => 'sqrt', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'pow' => ['handler' => 'php_fn', 'fn' => 'pow', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 1], + 'log' => ['handler' => 'php_fn', 'fn' => 'log', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 1], + 'log10' => ['handler' => 'php_fn', 'fn' => 'log10', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'exp' => ['handler' => 'php_fn', 'fn' => 'exp', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'sin' => ['handler' => 'php_fn', 'fn' => 'sin', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'cos' => ['handler' => 'php_fn', 'fn' => 'cos', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'tan' => ['handler' => 'php_fn', 'fn' => 'tan', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'asin' => ['handler' => 'php_fn', 'fn' => 'asin', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'acos' => ['handler' => 'php_fn', 'fn' => 'acos', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'atan' => ['handler' => 'php_fn', 'fn' => 'atan', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'atan2' => ['handler' => 'php_fn', 'fn' => 'atan2', 'return_type' => Type::FLOAT, 'min_args' => 1, 'max_args' => 1], + 'deg2rad' => ['handler' => 'php_fn', 'fn' => 'deg2rad', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'rad2deg' => ['handler' => 'php_fn', 'fn' => 'rad2deg', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'max' => ['handler' => 'php_fn', 'fn' => 'max', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'min' => ['handler' => 'php_fn', 'fn' => 'min', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], ], - CompilerBase::TYPE_FLOAT => [ - 'add' => ['handler' => 'calc_op', 'op' => '+', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], - 'sub' => ['handler' => 'calc_op', 'op' => '-', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], - 'mul' => ['handler' => 'calc_op', 'op' => '*', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], - 'div' => ['handler' => 'calc_op', 'op' => '/', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], - 'inc' => ['handler' => 'calc_inc', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'dec' => ['handler' => 'calc_dec', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], + Type::FLOAT => [ + 'add' => ['handler' => 'calc_op', 'op' => '+', 'return_type' => Type::FLOAT, 'min_args' => 1, 'max_args' => 1], + 'sub' => ['handler' => 'calc_op', 'op' => '-', 'return_type' => Type::FLOAT, 'min_args' => 1, 'max_args' => 1], + 'mul' => ['handler' => 'calc_op', 'op' => '*', 'return_type' => Type::FLOAT, 'min_args' => 1, 'max_args' => 1], + 'div' => ['handler' => 'calc_op', 'op' => '/', 'return_type' => Type::FLOAT, 'min_args' => 1, 'max_args' => 1], + 'inc' => ['handler' => 'calc_inc', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'dec' => ['handler' => 'calc_dec', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], // math - 'abs' => ['handler' => 'php_fn', 'fn' => 'abs', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'ceil' => ['handler' => 'php_fn', 'fn' => 'ceil', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'floor' => ['handler' => 'php_fn', 'fn' => 'floor', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'round' => ['handler' => 'php_fn', 'fn' => 'round', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 2], - 'sqrt' => ['handler' => 'php_fn', 'fn' => 'sqrt', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'pow' => ['handler' => 'php_fn', 'fn' => 'pow', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], - 'log' => ['handler' => 'php_fn', 'fn' => 'log', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 1], - 'log10' => ['handler' => 'php_fn', 'fn' => 'log10', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'exp' => ['handler' => 'php_fn', 'fn' => 'exp', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'sin' => ['handler' => 'php_fn', 'fn' => 'sin', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'cos' => ['handler' => 'php_fn', 'fn' => 'cos', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'tan' => ['handler' => 'php_fn', 'fn' => 'tan', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'asin' => ['handler' => 'php_fn', 'fn' => 'asin', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'acos' => ['handler' => 'php_fn', 'fn' => 'acos', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'atan' => ['handler' => 'php_fn', 'fn' => 'atan', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'atan2' => ['handler' => 'php_fn', 'fn' => 'atan2', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], - 'deg2rad' => ['handler' => 'php_fn', 'fn' => 'deg2rad', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'rad2deg' => ['handler' => 'php_fn', 'fn' => 'rad2deg', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], - 'max' => ['handler' => 'php_fn', 'fn' => 'max', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], - 'min' => ['handler' => 'php_fn', 'fn' => 'min', 'return_type' => CompilerBase::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], + 'abs' => ['handler' => 'php_fn', 'fn' => 'abs', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'ceil' => ['handler' => 'php_fn', 'fn' => 'ceil', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'floor' => ['handler' => 'php_fn', 'fn' => 'floor', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'round' => ['handler' => 'php_fn', 'fn' => 'round', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 2], + 'sqrt' => ['handler' => 'php_fn', 'fn' => 'sqrt', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'pow' => ['handler' => 'php_fn', 'fn' => 'pow', 'return_type' => Type::FLOAT, 'min_args' => 1, 'max_args' => 1], + 'log' => ['handler' => 'php_fn', 'fn' => 'log', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 1], + 'log10' => ['handler' => 'php_fn', 'fn' => 'log10', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'exp' => ['handler' => 'php_fn', 'fn' => 'exp', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'sin' => ['handler' => 'php_fn', 'fn' => 'sin', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'cos' => ['handler' => 'php_fn', 'fn' => 'cos', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'tan' => ['handler' => 'php_fn', 'fn' => 'tan', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'asin' => ['handler' => 'php_fn', 'fn' => 'asin', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'acos' => ['handler' => 'php_fn', 'fn' => 'acos', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'atan' => ['handler' => 'php_fn', 'fn' => 'atan', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'atan2' => ['handler' => 'php_fn', 'fn' => 'atan2', 'return_type' => Type::FLOAT, 'min_args' => 1, 'max_args' => 1], + 'deg2rad' => ['handler' => 'php_fn', 'fn' => 'deg2rad', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'rad2deg' => ['handler' => 'php_fn', 'fn' => 'rad2deg', 'return_type' => Type::FLOAT, 'min_args' => 0, 'max_args' => 0], + 'max' => ['handler' => 'php_fn', 'fn' => 'max', 'return_type' => Type::FLOAT, 'min_args' => 1, 'max_args' => 1], + 'min' => ['handler' => 'php_fn', 'fn' => 'min', 'return_type' => Type::FLOAT, 'min_args' => 1, 'max_args' => 1], ], - CompilerBase::TYPE_BOOL => [ + Type::BOOL => [ ], - CompilerBase::TYPE_STR => [ + Type::STR => [ // --- stdext string_methods (all use PHP standard functions) --- - 'length' => ['handler' => 'php_fn', 'fn' => 'strlen', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 0, 'max_args' => 0], - 'isEmpty' => ['handler' => 'direct_method', 'method' => 'empty', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], - 'lower' => ['handler' => 'php_fn', 'fn' => 'strtolower', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'upper' => ['handler' => 'php_fn', 'fn' => 'strtoupper', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'lowerFirst' => ['handler' => 'php_fn', 'fn' => 'lcfirst', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'upperFirst' => ['handler' => 'php_fn', 'fn' => 'ucfirst', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'upperWords' => ['handler' => 'php_fn', 'fn' => 'ucwords', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'addCSlashes' => ['handler' => 'php_fn', 'fn' => 'addcslashes', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 1], - 'addSlashes' => ['handler' => 'php_fn', 'fn' => 'addslashes', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'chunkSplit' => ['handler' => 'php_fn', 'fn' => 'chunk_split', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 2], - 'countChars' => ['handler' => 'php_fn', 'fn' => 'count_chars', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 1], - 'htmlEntityDecode' => ['handler' => 'php_fn', 'fn' => 'html_entity_decode', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 2], - 'htmlEntityEncode' => ['handler' => 'php_fn', 'fn' => 'htmlentities', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 3], - 'htmlSpecialCharsEncode' => ['handler' => 'php_fn', 'fn' => 'htmlspecialchars', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 3], - 'htmlSpecialCharsDecode' => ['handler' => 'php_fn', 'fn' => 'htmlspecialchars_decode', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'trim' => ['handler' => 'php_fn', 'fn' => 'trim', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 2], - 'lTrim' => ['handler' => 'php_fn', 'fn' => 'ltrim', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'rTrim' => ['handler' => 'php_fn', 'fn' => 'rtrim', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'parseStr' => ['handler' => 'cpp_fn', 'fn' => 'php::fn::parse_str', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], - 'parseUrl' => ['handler' => 'php_fn', 'fn' => 'parse_url', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 1], - 'contains' => ['handler' => 'php_fn', 'fn' => 'str_contains', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 1, 'max_args' => 1], - 'incr' => ['handler' => 'php_fn', 'fn' => 'str_increment', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'decr' => ['handler' => 'php_fn', 'fn' => 'str_decrement', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'pad' => ['handler' => 'php_fn', 'fn' => 'str_pad', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 3], - 'repeat' => ['handler' => 'php_fn', 'fn' => 'str_repeat', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 1], - 'replace' => ['handler' => 'php_fn', 'fn' => 'str_replace', 'receiver_pos' => 3, 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 2, 'max_args' => 3], - 'iReplace' => ['handler' => 'php_fn', 'fn' => 'str_ireplace', 'receiver_pos' => 3, 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 2, 'max_args' => 3], - 'shuffle' => ['handler' => 'php_fn', 'fn' => 'str_shuffle', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'split' => ['handler' => 'php_fn', 'fn' => 'explode', 'receiver_pos' => 2, 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 2], - 'startsWith' => ['handler' => 'php_fn', 'fn' => 'str_starts_with', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 1, 'max_args' => 1], - 'endsWith' => ['handler' => 'php_fn', 'fn' => 'str_ends_with', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 1, 'max_args' => 1], - 'wordCount' => ['handler' => 'php_fn', 'fn' => 'str_word_count', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 2], - 'iCompare' => ['handler' => 'php_fn', 'fn' => 'strcasecmp', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'compare' => ['handler' => 'php_fn', 'fn' => 'strcmp', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'find' => ['handler' => 'php_fn', 'fn' => 'strstr', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], - 'iFind' => ['handler' => 'php_fn', 'fn' => 'stristr', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], - 'stripTags' => ['handler' => 'php_fn', 'fn' => 'strip_tags', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 2], - 'stripCSlashes' => ['handler' => 'php_fn', 'fn' => 'stripcslashes', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'stripSlashes' => ['handler' => 'php_fn', 'fn' => 'stripslashes', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'iIndexOf' => ['handler' => 'php_fn', 'fn' => 'stripos', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], - 'indexOf' => ['handler' => 'php_fn', 'fn' => 'strpos', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], - 'lastIndexOf' => ['handler' => 'php_fn', 'fn' => 'strrpos', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], - 'iLastIndexOf' => ['handler' => 'php_fn', 'fn' => 'strripos', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], - 'lastCharIndexOf' => ['handler' => 'php_fn', 'fn' => 'strrchr', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 1], - 'substr' => ['handler' => 'php_fn', 'fn' => 'substr', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 2], - 'substrCompare' => ['handler' => 'php_fn', 'fn' => 'substr_compare', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 4], - 'substrCount' => ['handler' => 'php_fn', 'fn' => 'substr_count', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 3], - 'substrReplace' => ['handler' => 'php_fn', 'fn' => 'substr_replace', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 3], - 'reverse' => ['handler' => 'php_fn', 'fn' => 'strrev', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'md5' => ['handler' => 'php_fn', 'fn' => 'md5', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'sha1' => ['handler' => 'php_fn', 'fn' => 'sha1', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'crc32' => ['handler' => 'php_fn', 'fn' => 'crc32', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 0, 'max_args' => 0], - 'hash' => ['handler' => 'php_fn', 'fn' => 'hash', 'receiver_pos' => 2, 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 2], - 'hashCode' => ['handler' => 'direct_method', 'method' => 'hashCode', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 0, 'max_args' => 0], - 'base64Decode' => ['handler' => 'php_fn', 'fn' => 'base64_decode', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'base64Encode' => ['handler' => 'php_fn', 'fn' => 'base64_encode', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'urlDecode' => ['handler' => 'php_fn', 'fn' => 'urldecode', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'urlEncode' => ['handler' => 'php_fn', 'fn' => 'urlencode', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'rawUrlEncode' => ['handler' => 'php_fn', 'fn' => 'rawurlencode', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'rawUrlDecode' => ['handler' => 'php_fn', 'fn' => 'rawurldecode', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'match' => ['handler' => 'direct_method', 'method' => 'match', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 3, 'int_cast_args' => [1, 2]], - 'matchAll' => ['handler' => 'direct_method', 'method' => 'matchAll', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 3, 'int_cast_args' => [1, 2]], - 'isNumeric' => ['handler' => 'php_fn', 'fn' => 'is_numeric', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], + 'length' => ['handler' => 'php_fn', 'fn' => 'strlen', 'return_type' => Type::INT, 'min_args' => 0, 'max_args' => 0], + 'isEmpty' => ['handler' => 'direct_method', 'method' => 'empty', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 0], + 'lower' => ['handler' => 'php_fn', 'fn' => 'strtolower', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'upper' => ['handler' => 'php_fn', 'fn' => 'strtoupper', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'lowerFirst' => ['handler' => 'php_fn', 'fn' => 'lcfirst', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'upperFirst' => ['handler' => 'php_fn', 'fn' => 'ucfirst', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'upperWords' => ['handler' => 'php_fn', 'fn' => 'ucwords', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'addCSlashes' => ['handler' => 'php_fn', 'fn' => 'addcslashes', 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 1], + 'addSlashes' => ['handler' => 'php_fn', 'fn' => 'addslashes', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'chunkSplit' => ['handler' => 'php_fn', 'fn' => 'chunk_split', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 2], + 'countChars' => ['handler' => 'php_fn', 'fn' => 'count_chars', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 1], + 'htmlEntityDecode' => ['handler' => 'php_fn', 'fn' => 'html_entity_decode', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 2], + 'htmlEntityEncode' => ['handler' => 'php_fn', 'fn' => 'htmlentities', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 3], + 'htmlSpecialCharsEncode' => ['handler' => 'php_fn', 'fn' => 'htmlspecialchars', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 3], + 'htmlSpecialCharsDecode' => ['handler' => 'php_fn', 'fn' => 'htmlspecialchars_decode', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'trim' => ['handler' => 'php_fn', 'fn' => 'trim', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 2], + 'lTrim' => ['handler' => 'php_fn', 'fn' => 'ltrim', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'rTrim' => ['handler' => 'php_fn', 'fn' => 'rtrim', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'parseStr' => ['handler' => 'cpp_fn', 'fn' => 'php::fn::parse_str', 'return_type' => Type::ARRAY, 'min_args' => 0, 'max_args' => 0], + 'parseUrl' => ['handler' => 'php_fn', 'fn' => 'parse_url', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 1], + 'contains' => ['handler' => 'php_fn', 'fn' => 'str_contains', 'return_type' => Type::BOOL, 'min_args' => 1, 'max_args' => 1], + 'incr' => ['handler' => 'php_fn', 'fn' => 'str_increment', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'decr' => ['handler' => 'php_fn', 'fn' => 'str_decrement', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'pad' => ['handler' => 'php_fn', 'fn' => 'str_pad', 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 3], + 'repeat' => ['handler' => 'php_fn', 'fn' => 'str_repeat', 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 1], + 'replace' => ['handler' => 'php_fn', 'fn' => 'str_replace', 'receiver_pos' => 3, 'return_type' => Type::STR, 'min_args' => 2, 'max_args' => 3], + 'iReplace' => ['handler' => 'php_fn', 'fn' => 'str_ireplace', 'receiver_pos' => 3, 'return_type' => Type::STR, 'min_args' => 2, 'max_args' => 3], + 'shuffle' => ['handler' => 'php_fn', 'fn' => 'str_shuffle', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'split' => ['handler' => 'php_fn', 'fn' => 'explode', 'receiver_pos' => 2, 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 2], + 'startsWith' => ['handler' => 'php_fn', 'fn' => 'str_starts_with', 'return_type' => Type::BOOL, 'min_args' => 1, 'max_args' => 1], + 'endsWith' => ['handler' => 'php_fn', 'fn' => 'str_ends_with', 'return_type' => Type::BOOL, 'min_args' => 1, 'max_args' => 1], + 'wordCount' => ['handler' => 'php_fn', 'fn' => 'str_word_count', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 2], + 'iCompare' => ['handler' => 'php_fn', 'fn' => 'strcasecmp', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'compare' => ['handler' => 'php_fn', 'fn' => 'strcmp', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'find' => ['handler' => 'php_fn', 'fn' => 'strstr', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 2], + 'iFind' => ['handler' => 'php_fn', 'fn' => 'stristr', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 2], + 'stripTags' => ['handler' => 'php_fn', 'fn' => 'strip_tags', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 2], + 'stripCSlashes' => ['handler' => 'php_fn', 'fn' => 'stripcslashes', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'stripSlashes' => ['handler' => 'php_fn', 'fn' => 'stripslashes', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'iIndexOf' => ['handler' => 'php_fn', 'fn' => 'stripos', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 2], + 'indexOf' => ['handler' => 'php_fn', 'fn' => 'strpos', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 2], + 'lastIndexOf' => ['handler' => 'php_fn', 'fn' => 'strrpos', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 2], + 'iLastIndexOf' => ['handler' => 'php_fn', 'fn' => 'strripos', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 2], + 'lastCharIndexOf' => ['handler' => 'php_fn', 'fn' => 'strrchr', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 1], + 'substr' => ['handler' => 'php_fn', 'fn' => 'substr', 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 2], + 'substrCompare' => ['handler' => 'php_fn', 'fn' => 'substr_compare', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 4], + 'substrCount' => ['handler' => 'php_fn', 'fn' => 'substr_count', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 3], + 'substrReplace' => ['handler' => 'php_fn', 'fn' => 'substr_replace', 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 3], + 'reverse' => ['handler' => 'php_fn', 'fn' => 'strrev', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'md5' => ['handler' => 'php_fn', 'fn' => 'md5', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'sha1' => ['handler' => 'php_fn', 'fn' => 'sha1', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'crc32' => ['handler' => 'php_fn', 'fn' => 'crc32', 'return_type' => Type::INT, 'min_args' => 0, 'max_args' => 0], + 'hash' => ['handler' => 'php_fn', 'fn' => 'hash', 'receiver_pos' => 2, 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 2], + 'hashCode' => ['handler' => 'direct_method', 'method' => 'hashCode', 'return_type' => Type::INT, 'min_args' => 0, 'max_args' => 0], + 'base64Decode' => ['handler' => 'php_fn', 'fn' => 'base64_decode', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'base64Encode' => ['handler' => 'php_fn', 'fn' => 'base64_encode', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'urlDecode' => ['handler' => 'php_fn', 'fn' => 'urldecode', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'urlEncode' => ['handler' => 'php_fn', 'fn' => 'urlencode', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'rawUrlEncode' => ['handler' => 'php_fn', 'fn' => 'rawurlencode', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'rawUrlDecode' => ['handler' => 'php_fn', 'fn' => 'rawurldecode', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'match' => ['handler' => 'direct_method', 'method' => 'match', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 3, 'int_cast_args' => [1, 2]], + 'matchAll' => ['handler' => 'direct_method', 'method' => 'matchAll', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 3, 'int_cast_args' => [1, 2]], + 'isNumeric' => ['handler' => 'php_fn', 'fn' => 'is_numeric', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 0], // mbstring - 'mbUpperFirst' => ['handler' => 'php_fn', 'fn' => 'mb_ucfirst', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'mbLowerFirst' => ['handler' => 'php_fn', 'fn' => 'mb_lcfirst', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'mbTrim' => ['handler' => 'php_fn', 'fn' => 'mb_trim', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'mbSubstrCount' => ['handler' => 'php_fn', 'fn' => 'mb_substr_count', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 2], - 'mbSubstr' => ['handler' => 'php_fn', 'fn' => 'mb_substr', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 3], - 'mbUpper' => ['handler' => 'php_fn', 'fn' => 'mb_strtoupper', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'mbLower' => ['handler' => 'php_fn', 'fn' => 'mb_strtolower', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'mbFind' => ['handler' => 'php_fn', 'fn' => 'mb_strstr', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], - 'mbIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_strpos', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], - 'mbLastIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_strrpos', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], - 'mbILastIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_strripos', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], - 'mbLastCharIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_strrchr', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], - 'mbILastCharIndex' => ['handler' => 'php_fn', 'fn' => 'mb_strrichr', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], - 'mbLength' => ['handler' => 'php_fn', 'fn' => 'mb_strlen', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 0, 'max_args' => 1], - 'mbIFind' => ['handler' => 'php_fn', 'fn' => 'mb_stristr', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], - 'mbIIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_stripos', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], - 'mbCut' => ['handler' => 'php_fn', 'fn' => 'mb_strcut', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 3], - 'mbRTrim' => ['handler' => 'php_fn', 'fn' => 'mb_rtrim', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'mbLTrim' => ['handler' => 'php_fn', 'fn' => 'mb_ltrim', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], - 'mbDetectEncoding' => ['handler' => 'php_fn', 'fn' => 'mb_detect_encoding', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 2], - 'mbConvertEncoding' => ['handler' => 'php_fn', 'fn' => 'mb_convert_encoding', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 2], - 'mbConvertCase' => ['handler' => 'php_fn', 'fn' => 'mb_convert_case', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 2], + 'mbUpperFirst' => ['handler' => 'php_fn', 'fn' => 'mb_ucfirst', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'mbLowerFirst' => ['handler' => 'php_fn', 'fn' => 'mb_lcfirst', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'mbTrim' => ['handler' => 'php_fn', 'fn' => 'mb_trim', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'mbSubstrCount' => ['handler' => 'php_fn', 'fn' => 'mb_substr_count', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 2], + 'mbSubstr' => ['handler' => 'php_fn', 'fn' => 'mb_substr', 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 3], + 'mbUpper' => ['handler' => 'php_fn', 'fn' => 'mb_strtoupper', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'mbLower' => ['handler' => 'php_fn', 'fn' => 'mb_strtolower', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'mbFind' => ['handler' => 'php_fn', 'fn' => 'mb_strstr', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 3], + 'mbIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_strpos', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 3], + 'mbLastIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_strrpos', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 3], + 'mbILastIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_strripos', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 3], + 'mbLastCharIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_strrchr', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 3], + 'mbILastCharIndex' => ['handler' => 'php_fn', 'fn' => 'mb_strrichr', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 3], + 'mbLength' => ['handler' => 'php_fn', 'fn' => 'mb_strlen', 'return_type' => Type::INT, 'min_args' => 0, 'max_args' => 1], + 'mbIFind' => ['handler' => 'php_fn', 'fn' => 'mb_stristr', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 3], + 'mbIIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_stripos', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 3], + 'mbCut' => ['handler' => 'php_fn', 'fn' => 'mb_strcut', 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 3], + 'mbRTrim' => ['handler' => 'php_fn', 'fn' => 'mb_rtrim', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'mbLTrim' => ['handler' => 'php_fn', 'fn' => 'mb_ltrim', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], + 'mbDetectEncoding' => ['handler' => 'php_fn', 'fn' => 'mb_detect_encoding', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 2], + 'mbConvertEncoding' => ['handler' => 'php_fn', 'fn' => 'mb_convert_encoding', 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 2], + 'mbConvertCase' => ['handler' => 'php_fn', 'fn' => 'mb_convert_case', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 2], // serialize - 'unserialize' => ['handler' => 'php_fn', 'fn' => 'unserialize', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], - 'unmarshal' => ['handler' => 'php_fn', 'fn' => 'unserialize', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], - 'jsonDecode' => ['handler' => 'php_fn', 'fn' => 'json_decode', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 2, 'const_args' => [1 => 'true']], - 'jsonDecodeToObject' => ['handler' => 'php_fn', 'fn' => 'json_decode', 'return_type' => CompilerBase::TYPE_OBJECT, 'min_args' => 0, 'max_args' => 2, 'const_args' => [1 => 'false']], + 'unserialize' => ['handler' => 'php_fn', 'fn' => 'unserialize', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 0], + 'unmarshal' => ['handler' => 'php_fn', 'fn' => 'unserialize', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 0], + 'jsonDecode' => ['handler' => 'php_fn', 'fn' => 'json_decode', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 2, 'const_args' => [1 => 'true']], + 'jsonDecodeToObject' => ['handler' => 'php_fn', 'fn' => 'json_decode', 'return_type' => Type::OBJECT, 'min_args' => 0, 'max_args' => 2, 'const_args' => [1 => 'false']], // phpx C++ methods (no PHP function equivalent) - 'equals' => ['handler' => 'direct_method', 'method' => 'equals', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 1, 'max_args' => 2], + 'equals' => ['handler' => 'direct_method', 'method' => 'equals', 'return_type' => Type::BOOL, 'min_args' => 1, 'max_args' => 2], ], - CompilerBase::TYPE_ARRAY => [ + Type::ARRAY => [ // --- stdext array_methods (all use PHP standard functions) --- - 'all' => ['handler' => 'php_fn', 'fn' => 'array_all', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 1], - 'any' => ['handler' => 'php_fn', 'fn' => 'array_any', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 1], - 'changeKeyCase' => ['handler' => 'php_fn', 'fn' => 'array_change_key_case', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 1], - 'chunk' => ['handler' => 'php_fn', 'fn' => 'array_chunk', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 2], - 'column' => ['handler' => 'php_fn', 'fn' => 'array_column', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 2], - 'countValues' => ['handler' => 'php_fn', 'fn' => 'array_count_values', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], - 'diff' => ['handler' => 'php_fn', 'fn' => 'array_diff', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], - 'diffAssoc' => ['handler' => 'php_fn', 'fn' => 'array_diff_assoc', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], - 'diffKey' => ['handler' => 'php_fn', 'fn' => 'array_diff_key', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], - 'filter' => ['handler' => 'php_fn', 'fn' => 'array_filter', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 2], - 'find' => ['handler' => 'php_fn', 'fn' => 'array_find', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 1], - 'flip' => ['handler' => 'php_fn', 'fn' => 'array_flip', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], - 'intersect' => ['handler' => 'php_fn', 'fn' => 'array_intersect', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], - 'intersectAssoc' => ['handler' => 'php_fn', 'fn' => 'array_intersect_assoc', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], - 'isList' => ['handler' => 'php_fn', 'fn' => 'array_is_list', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], - 'keyExists' => ['handler' => 'php_fn', 'fn' => 'array_key_exists', 'receiver_pos' => 2, 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 1, 'max_args' => 1], - 'keyFirst' => ['handler' => 'php_fn', 'fn' => 'array_key_first', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], - 'keyLast' => ['handler' => 'php_fn', 'fn' => 'array_key_last', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], - 'keys' => ['handler' => 'php_fn', 'fn' => 'array_keys', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 2], - 'map' => ['handler' => 'php_fn', 'fn' => 'array_map', 'receiver_pos' => 2, 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], - 'pad' => ['handler' => 'php_fn', 'fn' => 'array_pad', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 2, 'max_args' => 2], - 'product' => ['handler' => 'php_fn', 'fn' => 'array_product', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], - 'rand' => ['handler' => 'php_fn', 'fn' => 'array_rand', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 1], - 'reduce' => ['handler' => 'php_fn', 'fn' => 'array_reduce', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], - 'replace' => ['handler' => 'php_fn', 'fn' => 'array_replace', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], - 'reverse' => ['handler' => 'php_fn', 'fn' => 'array_reverse', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 1], - 'search' => ['handler' => 'php_fn', 'fn' => 'array_search', 'receiver_pos' => 2, 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], - 'slice' => ['handler' => 'php_fn', 'fn' => 'array_slice', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 3], - 'sum' => ['handler' => 'php_fn', 'fn' => 'array_sum', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], - 'unique' => ['handler' => 'php_fn', 'fn' => 'array_unique', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 1], - 'values' => ['handler' => 'php_fn', 'fn' => 'array_values', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], - 'count' => ['handler' => 'php_fn', 'fn' => 'count', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 0, 'max_args' => 0], - 'merge' => ['handler' => 'php_fn', 'fn' => 'array_merge', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], - 'contains' => ['handler' => 'php_fn', 'fn' => 'in_array', 'receiver_pos' => 2, 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 1, 'max_args' => 2], - 'join' => ['handler' => 'php_fn', 'fn' => 'implode', 'receiver_pos' => 2, 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 1], - 'isEmpty' => ['handler' => 'direct_method', 'method' => 'empty', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], + 'all' => ['handler' => 'php_fn', 'fn' => 'array_all', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 1], + 'any' => ['handler' => 'php_fn', 'fn' => 'array_any', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 1], + 'changeKeyCase' => ['handler' => 'php_fn', 'fn' => 'array_change_key_case', 'return_type' => Type::ARRAY, 'min_args' => 0, 'max_args' => 1], + 'chunk' => ['handler' => 'php_fn', 'fn' => 'array_chunk', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 2], + 'column' => ['handler' => 'php_fn', 'fn' => 'array_column', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 2], + 'countValues' => ['handler' => 'php_fn', 'fn' => 'array_count_values', 'return_type' => Type::ARRAY, 'min_args' => 0, 'max_args' => 0], + 'diff' => ['handler' => 'php_fn', 'fn' => 'array_diff', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => -1], + 'diffAssoc' => ['handler' => 'php_fn', 'fn' => 'array_diff_assoc', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => -1], + 'diffKey' => ['handler' => 'php_fn', 'fn' => 'array_diff_key', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => -1], + 'filter' => ['handler' => 'php_fn', 'fn' => 'array_filter', 'return_type' => Type::ARRAY, 'min_args' => 0, 'max_args' => 2], + 'find' => ['handler' => 'php_fn', 'fn' => 'array_find', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 1], + 'flip' => ['handler' => 'php_fn', 'fn' => 'array_flip', 'return_type' => Type::ARRAY, 'min_args' => 0, 'max_args' => 0], + 'intersect' => ['handler' => 'php_fn', 'fn' => 'array_intersect', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => -1], + 'intersectAssoc' => ['handler' => 'php_fn', 'fn' => 'array_intersect_assoc', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => -1], + 'isList' => ['handler' => 'php_fn', 'fn' => 'array_is_list', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 0], + 'keyExists' => ['handler' => 'php_fn', 'fn' => 'array_key_exists', 'receiver_pos' => 2, 'return_type' => Type::BOOL, 'min_args' => 1, 'max_args' => 1], + 'keyFirst' => ['handler' => 'php_fn', 'fn' => 'array_key_first', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 0], + 'keyLast' => ['handler' => 'php_fn', 'fn' => 'array_key_last', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 0], + 'keys' => ['handler' => 'php_fn', 'fn' => 'array_keys', 'return_type' => Type::ARRAY, 'min_args' => 0, 'max_args' => 2], + 'map' => ['handler' => 'php_fn', 'fn' => 'array_map', 'receiver_pos' => 2, 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => -1], + 'pad' => ['handler' => 'php_fn', 'fn' => 'array_pad', 'return_type' => Type::ARRAY, 'min_args' => 2, 'max_args' => 2], + 'product' => ['handler' => 'php_fn', 'fn' => 'array_product', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 0], + 'rand' => ['handler' => 'php_fn', 'fn' => 'array_rand', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 1], + 'reduce' => ['handler' => 'php_fn', 'fn' => 'array_reduce', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 2], + 'replace' => ['handler' => 'php_fn', 'fn' => 'array_replace', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => -1], + 'reverse' => ['handler' => 'php_fn', 'fn' => 'array_reverse', 'return_type' => Type::ARRAY, 'min_args' => 0, 'max_args' => 1], + 'search' => ['handler' => 'php_fn', 'fn' => 'array_search', 'receiver_pos' => 2, 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 2], + 'slice' => ['handler' => 'php_fn', 'fn' => 'array_slice', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 3], + 'sum' => ['handler' => 'php_fn', 'fn' => 'array_sum', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 0], + 'unique' => ['handler' => 'php_fn', 'fn' => 'array_unique', 'return_type' => Type::ARRAY, 'min_args' => 0, 'max_args' => 1], + 'values' => ['handler' => 'php_fn', 'fn' => 'array_values', 'return_type' => Type::ARRAY, 'min_args' => 0, 'max_args' => 0], + 'count' => ['handler' => 'php_fn', 'fn' => 'count', 'return_type' => Type::INT, 'min_args' => 0, 'max_args' => 0], + 'merge' => ['handler' => 'php_fn', 'fn' => 'array_merge', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => -1], + 'contains' => ['handler' => 'php_fn', 'fn' => 'in_array', 'receiver_pos' => 2, 'return_type' => Type::BOOL, 'min_args' => 1, 'max_args' => 2], + 'join' => ['handler' => 'php_fn', 'fn' => 'implode', 'receiver_pos' => 2, 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 1], + 'isEmpty' => ['handler' => 'direct_method', 'method' => 'empty', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 0], // mutating via PHP reference functions - 'sort' => ['handler' => 'php_fn_ref', 'fn' => 'sort', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 1], - 'pop' => ['handler' => 'php_fn_ref', 'fn' => 'array_pop', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], - 'push' => ['handler' => 'php_fn_ref', 'fn' => 'array_push', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => -1], - 'shift' => ['handler' => 'php_fn_ref', 'fn' => 'array_shift', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], - 'unshift' => ['handler' => 'php_fn_ref', 'fn' => 'array_unshift', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => -1], - 'splice' => ['handler' => 'php_fn_ref', 'fn' => 'array_splice', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 3], - 'walk' => ['handler' => 'php_fn_ref', 'fn' => 'array_walk', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 1, 'max_args' => 2], - 'sortDesc' => ['handler' => 'php_fn_ref', 'fn' => 'rsort', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 1], - 'keySort' => ['handler' => 'php_fn_ref', 'fn' => 'ksort', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 1], - 'valueSort' => ['handler' => 'php_fn_ref', 'fn' => 'asort', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 1], - 'combine' => ['handler' => 'php_fn', 'fn' => 'array_combine', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 1], - 'fillKeys' => ['handler' => 'php_fn', 'fn' => 'array_fill_keys', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 1], - 'replaceStr' => ['handler' => 'php_fn', 'fn' => 'str_replace', 'receiver_pos' => 3, 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 2], - 'iReplaceStr' => ['handler' => 'php_fn', 'fn' => 'str_ireplace', 'receiver_pos' => 3, 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 2], + 'sort' => ['handler' => 'php_fn_ref', 'fn' => 'sort', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 1], + 'pop' => ['handler' => 'php_fn_ref', 'fn' => 'array_pop', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 0], + 'push' => ['handler' => 'php_fn_ref', 'fn' => 'array_push', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => -1], + 'shift' => ['handler' => 'php_fn_ref', 'fn' => 'array_shift', 'return_type' => Type::VAR, 'min_args' => 0, 'max_args' => 0], + 'unshift' => ['handler' => 'php_fn_ref', 'fn' => 'array_unshift', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => -1], + 'splice' => ['handler' => 'php_fn_ref', 'fn' => 'array_splice', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 3], + 'walk' => ['handler' => 'php_fn_ref', 'fn' => 'array_walk', 'return_type' => Type::BOOL, 'min_args' => 1, 'max_args' => 2], + 'sortDesc' => ['handler' => 'php_fn_ref', 'fn' => 'rsort', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 1], + 'keySort' => ['handler' => 'php_fn_ref', 'fn' => 'ksort', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 1], + 'valueSort' => ['handler' => 'php_fn_ref', 'fn' => 'asort', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 1], + 'combine' => ['handler' => 'php_fn', 'fn' => 'array_combine', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 1], + 'fillKeys' => ['handler' => 'php_fn', 'fn' => 'array_fill_keys', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 1], + 'replaceStr' => ['handler' => 'php_fn', 'fn' => 'str_replace', 'receiver_pos' => 3, 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 2], + 'iReplaceStr' => ['handler' => 'php_fn', 'fn' => 'str_ireplace', 'receiver_pos' => 3, 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 2], // serialize - 'serialize' => ['handler' => 'php_fn', 'fn' => 'serialize', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'marshal' => ['handler' => 'php_fn', 'fn' => 'serialize', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'jsonEncode' => ['handler' => 'php_fn', 'fn' => 'json_encode', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 2], + 'serialize' => ['handler' => 'php_fn', 'fn' => 'serialize', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'marshal' => ['handler' => 'php_fn', 'fn' => 'serialize', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'jsonEncode' => ['handler' => 'php_fn', 'fn' => 'json_encode', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 2], // phpx C++ methods (no PHP function equivalent) - 'set' => ['handler' => 'direct_method_mutate', 'method' => 'set', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 2, 'max_args' => 2], - 'get' => ['handler' => 'direct_method', 'method' => 'get', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 1], - 'del' => ['handler' => 'direct_method_mutate', 'method' => 'del', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 1], - 'clean' => ['handler' => 'direct_method_mutate', 'method' => 'clean', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], + 'set' => ['handler' => 'direct_method_mutate', 'method' => 'set', 'return_type' => Type::ARRAY, 'min_args' => 2, 'max_args' => 2], + 'get' => ['handler' => 'direct_method', 'method' => 'get', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 1], + 'del' => ['handler' => 'direct_method_mutate', 'method' => 'del', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 1], + 'clean' => ['handler' => 'direct_method_mutate', 'method' => 'clean', 'return_type' => Type::ARRAY, 'min_args' => 0, 'max_args' => 0], ], - CompilerBase::TYPE_STREAM => [ + Type::STREAM => [ // --- stdext stream_methods --- - 'write' => ['handler' => 'php_fn', 'fn' => 'fwrite', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 2], - 'read' => ['handler' => 'php_fn', 'fn' => 'fread', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 1], - 'close' => ['handler' => 'php_fn', 'fn' => 'fclose', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], - 'dataSync' => ['handler' => 'php_fn', 'fn' => 'fdatasync', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], - 'sync' => ['handler' => 'php_fn', 'fn' => 'fsync', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], - 'truncate' => ['handler' => 'php_fn', 'fn' => 'ftruncate', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 1], - 'stat' => ['handler' => 'php_fn', 'fn' => 'fstat', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], - 'seek' => ['handler' => 'php_fn', 'fn' => 'fseek', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 2], - 'tell' => ['handler' => 'php_fn', 'fn' => 'ftell', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 0, 'max_args' => 0], - 'lock' => ['handler' => 'php_fn', 'fn' => 'flock', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 1, 'max_args' => 2], - 'eof' => ['handler' => 'php_fn', 'fn' => 'feof', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], - 'getChar' => ['handler' => 'php_fn', 'fn' => 'fgetc', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 0], - 'getLine' => ['handler' => 'php_fn', 'fn' => 'fgets', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 1], + 'write' => ['handler' => 'php_fn', 'fn' => 'fwrite', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 2], + 'read' => ['handler' => 'php_fn', 'fn' => 'fread', 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 1], + 'close' => ['handler' => 'php_fn', 'fn' => 'fclose', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 0], + 'dataSync' => ['handler' => 'php_fn', 'fn' => 'fdatasync', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 0], + 'sync' => ['handler' => 'php_fn', 'fn' => 'fsync', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 0], + 'truncate' => ['handler' => 'php_fn', 'fn' => 'ftruncate', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 1], + 'stat' => ['handler' => 'php_fn', 'fn' => 'fstat', 'return_type' => Type::ARRAY, 'min_args' => 0, 'max_args' => 0], + 'seek' => ['handler' => 'php_fn', 'fn' => 'fseek', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 2], + 'tell' => ['handler' => 'php_fn', 'fn' => 'ftell', 'return_type' => Type::INT, 'min_args' => 0, 'max_args' => 0], + 'lock' => ['handler' => 'php_fn', 'fn' => 'flock', 'return_type' => Type::BOOL, 'min_args' => 1, 'max_args' => 2], + 'eof' => ['handler' => 'php_fn', 'fn' => 'feof', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 0], + 'getChar' => ['handler' => 'php_fn', 'fn' => 'fgetc', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 0], + 'getLine' => ['handler' => 'php_fn', 'fn' => 'fgets', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 1], // --- stream_* functions --- - 'getContents' => ['handler' => 'php_fn', 'fn' => 'stream_get_contents', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 2], - 'getMetaData' => ['handler' => 'php_fn', 'fn' => 'stream_get_meta_data', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], - 'isLocal' => ['handler' => 'php_fn', 'fn' => 'stream_is_local', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], - 'isTTY' => ['handler' => 'php_fn', 'fn' => 'stream_isatty', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], - 'setBlocking' => ['handler' => 'php_fn', 'fn' => 'stream_set_blocking', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 1, 'max_args' => 1], - 'setChunkSize' => ['handler' => 'php_fn', 'fn' => 'stream_set_chunk_size', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'setReadBuffer' => ['handler' => 'php_fn', 'fn' => 'stream_set_read_buffer', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'setTimeout' => ['handler' => 'php_fn', 'fn' => 'stream_set_timeout', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 1, 'max_args' => 2], - 'setWriteBuffer' => ['handler' => 'php_fn', 'fn' => 'stream_set_write_buffer', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'supportsLock' => ['handler' => 'php_fn', 'fn' => 'stream_supports_lock', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], - 'copy' => ['handler' => 'php_fn', 'fn' => 'stream_copy_to_stream', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 3], + 'getContents' => ['handler' => 'php_fn', 'fn' => 'stream_get_contents', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 2], + 'getMetaData' => ['handler' => 'php_fn', 'fn' => 'stream_get_meta_data', 'return_type' => Type::ARRAY, 'min_args' => 0, 'max_args' => 0], + 'isLocal' => ['handler' => 'php_fn', 'fn' => 'stream_is_local', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 0], + 'isTTY' => ['handler' => 'php_fn', 'fn' => 'stream_isatty', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 0], + 'setBlocking' => ['handler' => 'php_fn', 'fn' => 'stream_set_blocking', 'return_type' => Type::BOOL, 'min_args' => 1, 'max_args' => 1], + 'setChunkSize' => ['handler' => 'php_fn', 'fn' => 'stream_set_chunk_size', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'setReadBuffer' => ['handler' => 'php_fn', 'fn' => 'stream_set_read_buffer', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'setTimeout' => ['handler' => 'php_fn', 'fn' => 'stream_set_timeout', 'return_type' => Type::BOOL, 'min_args' => 1, 'max_args' => 2], + 'setWriteBuffer' => ['handler' => 'php_fn', 'fn' => 'stream_set_write_buffer', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'supportsLock' => ['handler' => 'php_fn', 'fn' => 'stream_supports_lock', 'return_type' => Type::BOOL, 'min_args' => 0, 'max_args' => 0], + 'copy' => ['handler' => 'php_fn', 'fn' => 'stream_copy_to_stream', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 3], // --- stream_socket_* functions --- - 'accept' => ['handler' => 'php_fn', 'fn' => 'stream_socket_accept', 'return_type' => CompilerBase::TYPE_STREAM, 'min_args' => 0, 'max_args' => 1], - 'enableCrypto' => ['handler' => 'php_fn', 'fn' => 'stream_socket_enable_crypto', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 3], - 'getSocketName' => ['handler' => 'php_fn', 'fn' => 'stream_socket_get_name', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 1], - 'recvFrom' => ['handler' => 'php_fn', 'fn' => 'stream_socket_recvfrom', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 1, 'max_args' => 2], - 'sendTo' => ['handler' => 'php_fn', 'fn' => 'stream_socket_sendto', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 3], - 'shutdown' => ['handler' => 'php_fn', 'fn' => 'stream_socket_shutdown', 'return_type' => CompilerBase::TYPE_BOOL, 'min_args' => 1, 'max_args' => 1], - 'getRecord' => ['handler' => 'php_fn', 'fn' => 'stream_get_line', 'return_type' => CompilerBase::TYPE_STR, 'min_args' => 0, 'max_args' => 2], + 'accept' => ['handler' => 'php_fn', 'fn' => 'stream_socket_accept', 'return_type' => Type::STREAM, 'min_args' => 0, 'max_args' => 1], + 'enableCrypto' => ['handler' => 'php_fn', 'fn' => 'stream_socket_enable_crypto', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 3], + 'getSocketName' => ['handler' => 'php_fn', 'fn' => 'stream_socket_get_name', 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 1], + 'recvFrom' => ['handler' => 'php_fn', 'fn' => 'stream_socket_recvfrom', 'return_type' => Type::STR, 'min_args' => 1, 'max_args' => 2], + 'sendTo' => ['handler' => 'php_fn', 'fn' => 'stream_socket_sendto', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 3], + 'shutdown' => ['handler' => 'php_fn', 'fn' => 'stream_socket_shutdown', 'return_type' => Type::BOOL, 'min_args' => 1, 'max_args' => 1], + 'getRecord' => ['handler' => 'php_fn', 'fn' => 'stream_get_line', 'return_type' => Type::STR, 'min_args' => 0, 'max_args' => 2], // --- stream filters --- - 'appendFilter' => ['handler' => 'php_fn', 'fn' => 'stream_filter_append', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], - 'prependFilter' => ['handler' => 'php_fn', 'fn' => 'stream_filter_prepend', 'return_type' => CompilerBase::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], + 'appendFilter' => ['handler' => 'php_fn', 'fn' => 'stream_filter_append', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 3], + 'prependFilter' => ['handler' => 'php_fn', 'fn' => 'stream_filter_prepend', 'return_type' => Type::VAR, 'min_args' => 1, 'max_args' => 3], ], - CompilerBase::TYPE_BIGINT => [ - 'add' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::add', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 1, 'max_args' => 1], - 'sub' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::sub', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 1, 'max_args' => 1], - 'mul' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::mul', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 1, 'max_args' => 1], - 'div' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::div', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 1, 'max_args' => 1], - 'mod' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::mod', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 1, 'max_args' => 1], - 'pow' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::pow', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 1, 'max_args' => 1], - 'neg' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::neg', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 0, 'max_args' => 0], - 'cmp' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::cmp', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'abs' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::abs', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 0, 'max_args' => 0], - 'gcd' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::gcd', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 1, 'max_args' => 1], - 'divmod' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::divmod', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 1], - 'powmod' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::powmod', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 2, 'max_args' => 2], - 'sqrt' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::sqrt', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 0, 'max_args' => 0], - 'bitAnd' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::bitAnd', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 1, 'max_args' => 1], - 'bitOr' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::bitOr', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 1, 'max_args' => 1], - 'bitXor' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::bitXor', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 1, 'max_args' => 1], - 'bitNot' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::bitNot', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 0, 'max_args' => 0], - 'testBit' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::testBit', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'popCount' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::popCount', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 0, 'max_args' => 0], - 'bitShiftLeft' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::bitShiftLeft', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 1, 'max_args' => 1], - 'bitShiftRight' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::bitShiftRight', 'return_type' => CompilerBase::TYPE_BIGINT, 'min_args' => 1, 'max_args' => 1], + Type::BIGINT => [ + 'add' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::add', 'return_type' => Type::BIGINT, 'min_args' => 1, 'max_args' => 1], + 'sub' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::sub', 'return_type' => Type::BIGINT, 'min_args' => 1, 'max_args' => 1], + 'mul' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::mul', 'return_type' => Type::BIGINT, 'min_args' => 1, 'max_args' => 1], + 'div' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::div', 'return_type' => Type::BIGINT, 'min_args' => 1, 'max_args' => 1], + 'mod' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::mod', 'return_type' => Type::BIGINT, 'min_args' => 1, 'max_args' => 1], + 'pow' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::pow', 'return_type' => Type::BIGINT, 'min_args' => 1, 'max_args' => 1], + 'neg' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::neg', 'return_type' => Type::BIGINT, 'min_args' => 0, 'max_args' => 0], + 'cmp' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::cmp', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'abs' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::abs', 'return_type' => Type::BIGINT, 'min_args' => 0, 'max_args' => 0], + 'gcd' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::gcd', 'return_type' => Type::BIGINT, 'min_args' => 1, 'max_args' => 1], + 'divmod' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::divmod', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 1], + 'powmod' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::powmod', 'return_type' => Type::BIGINT, 'min_args' => 2, 'max_args' => 2], + 'sqrt' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::sqrt', 'return_type' => Type::BIGINT, 'min_args' => 0, 'max_args' => 0], + 'bitAnd' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::bitAnd', 'return_type' => Type::BIGINT, 'min_args' => 1, 'max_args' => 1], + 'bitOr' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::bitOr', 'return_type' => Type::BIGINT, 'min_args' => 1, 'max_args' => 1], + 'bitXor' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::bitXor', 'return_type' => Type::BIGINT, 'min_args' => 1, 'max_args' => 1], + 'bitNot' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::bitNot', 'return_type' => Type::BIGINT, 'min_args' => 0, 'max_args' => 0], + 'testBit' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::testBit', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'popCount' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::popCount', 'return_type' => Type::INT, 'min_args' => 0, 'max_args' => 0], + 'bitShiftLeft' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::bitShiftLeft', 'return_type' => Type::BIGINT, 'min_args' => 1, 'max_args' => 1], + 'bitShiftRight' => ['handler' => 'cpp_fn', 'fn' => 'php::BigInt::bitShiftRight', 'return_type' => Type::BIGINT, 'min_args' => 1, 'max_args' => 1], ], - CompilerBase::TYPE_DECIMAL => [ - 'add' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::add', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 1, 'max_args' => 1], - 'sub' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::sub', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 1, 'max_args' => 1], - 'mul' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::mul', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 1, 'max_args' => 1], - 'div' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::div', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 1, 'max_args' => 1], - 'mod' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::mod', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 1, 'max_args' => 1], - 'pow' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::pow', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 1, 'max_args' => 1], - 'neg' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::neg', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 0, 'max_args' => 0], - 'cmp' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::cmp', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'abs' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::abs', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 0, 'max_args' => 0], - 'divmod' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::divmod', 'return_type' => CompilerBase::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 1], - 'powmod' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::powmod', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 2, 'max_args' => 2], - 'sqrt' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::sqrt', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 0, 'max_args' => 0], - 'floor' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::floor', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 0, 'max_args' => 0], - 'ceil' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::ceil', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 0, 'max_args' => 0], - 'round' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::round', 'return_type' => CompilerBase::TYPE_DECIMAL, 'min_args' => 0, 'max_args' => 1], + Type::DECIMAL => [ + 'add' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::add', 'return_type' => Type::DECIMAL, 'min_args' => 1, 'max_args' => 1], + 'sub' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::sub', 'return_type' => Type::DECIMAL, 'min_args' => 1, 'max_args' => 1], + 'mul' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::mul', 'return_type' => Type::DECIMAL, 'min_args' => 1, 'max_args' => 1], + 'div' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::div', 'return_type' => Type::DECIMAL, 'min_args' => 1, 'max_args' => 1], + 'mod' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::mod', 'return_type' => Type::DECIMAL, 'min_args' => 1, 'max_args' => 1], + 'pow' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::pow', 'return_type' => Type::DECIMAL, 'min_args' => 1, 'max_args' => 1], + 'neg' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::neg', 'return_type' => Type::DECIMAL, 'min_args' => 0, 'max_args' => 0], + 'cmp' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::cmp', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'abs' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::abs', 'return_type' => Type::DECIMAL, 'min_args' => 0, 'max_args' => 0], + 'divmod' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::divmod', 'return_type' => Type::ARRAY, 'min_args' => 1, 'max_args' => 1], + 'powmod' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::powmod', 'return_type' => Type::DECIMAL, 'min_args' => 2, 'max_args' => 2], + 'sqrt' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::sqrt', 'return_type' => Type::DECIMAL, 'min_args' => 0, 'max_args' => 0], + 'floor' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::floor', 'return_type' => Type::DECIMAL, 'min_args' => 0, 'max_args' => 0], + 'ceil' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::ceil', 'return_type' => Type::DECIMAL, 'min_args' => 0, 'max_args' => 0], + 'round' => ['handler' => 'cpp_fn', 'fn' => 'php::Decimal::round', 'return_type' => Type::DECIMAL, 'min_args' => 0, 'max_args' => 1], ], - CompilerBase::TYPE_BIGFLOAT => [ - 'add' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::add', 'return_type' => CompilerBase::TYPE_BIGFLOAT, 'min_args' => 1, 'max_args' => 1], - 'sub' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::sub', 'return_type' => CompilerBase::TYPE_BIGFLOAT, 'min_args' => 1, 'max_args' => 1], - 'mul' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::mul', 'return_type' => CompilerBase::TYPE_BIGFLOAT, 'min_args' => 1, 'max_args' => 1], - 'div' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::div', 'return_type' => CompilerBase::TYPE_BIGFLOAT, 'min_args' => 1, 'max_args' => 1], - 'neg' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::neg', 'return_type' => CompilerBase::TYPE_BIGFLOAT, 'min_args' => 0, 'max_args' => 0], - 'cmp' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::cmp', 'return_type' => CompilerBase::TYPE_INT, 'min_args' => 1, 'max_args' => 1], - 'abs' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::abs', 'return_type' => CompilerBase::TYPE_BIGFLOAT, 'min_args' => 0, 'max_args' => 0], - 'sqrt' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::sqrt', 'return_type' => CompilerBase::TYPE_BIGFLOAT, 'min_args' => 0, 'max_args' => 0], + Type::BIGFLOAT => [ + 'add' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::add', 'return_type' => Type::BIGFLOAT, 'min_args' => 1, 'max_args' => 1], + 'sub' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::sub', 'return_type' => Type::BIGFLOAT, 'min_args' => 1, 'max_args' => 1], + 'mul' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::mul', 'return_type' => Type::BIGFLOAT, 'min_args' => 1, 'max_args' => 1], + 'div' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::div', 'return_type' => Type::BIGFLOAT, 'min_args' => 1, 'max_args' => 1], + 'neg' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::neg', 'return_type' => Type::BIGFLOAT, 'min_args' => 0, 'max_args' => 0], + 'cmp' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::cmp', 'return_type' => Type::INT, 'min_args' => 1, 'max_args' => 1], + 'abs' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::abs', 'return_type' => Type::BIGFLOAT, 'min_args' => 0, 'max_args' => 0], + 'sqrt' => ['handler' => 'cpp_fn', 'fn' => 'php::BigFloat::sqrt', 'return_type' => Type::BIGFLOAT, 'min_args' => 0, 'max_args' => 0], ], ]; @@ -336,16 +338,16 @@ trait UniversalMethodCall } protected const array TYPE_EXTENSION_PREFIX = [ - CompilerBase::TYPE_INT => 'int', - CompilerBase::TYPE_FLOAT => 'float', - CompilerBase::TYPE_BOOL => 'bool', - CompilerBase::TYPE_STR => 'str', - CompilerBase::TYPE_ARRAY => 'array', - CompilerBase::TYPE_STREAM => 'stream', - CompilerBase::TYPE_BIGINT => 'bigint', - CompilerBase::TYPE_DECIMAL => 'decimal', - CompilerBase::TYPE_BIGFLOAT => 'bigfloat', - CompilerBase::TYPE_BOX => 'box', + Type::INT => 'int', + Type::FLOAT => 'float', + Type::BOOL => 'bool', + Type::STR => 'str', + Type::ARRAY => 'array', + Type::STREAM => 'stream', + Type::BIGINT => 'bigint', + Type::DECIMAL => 'decimal', + Type::BIGFLOAT => 'bigfloat', + Type::BOX => 'box', ]; protected function camelToSnake(string $name): string @@ -378,9 +380,9 @@ trait UniversalMethodCall } protected const array TO_CONVERT_FN = [ - CompilerBase::TYPE_BIGINT => ['toInt' => 'php::BigInt::toInt', 'toFloat' => 'php::BigInt::toFloat', 'toString' => 'php::BigInt::toString'], - CompilerBase::TYPE_BIGFLOAT => ['toInt' => 'php::BigFloat::toInt', 'toFloat' => 'php::BigFloat::toFloat', 'toString' => 'php::BigFloat::toString'], - CompilerBase::TYPE_DECIMAL => ['toInt' => 'php::Decimal::toInt', 'toFloat' => 'php::Decimal::toFloat', 'toString' => 'php::Decimal::toString'], + Type::BIGINT => ['toInt' => 'php::BigInt::toInt', 'toFloat' => 'php::BigInt::toFloat', 'toString' => 'php::BigInt::toString'], + Type::BIGFLOAT => ['toInt' => 'php::BigFloat::toInt', 'toFloat' => 'php::BigFloat::toFloat', 'toString' => 'php::BigFloat::toString'], + Type::DECIMAL => ['toInt' => 'php::Decimal::toInt', 'toFloat' => 'php::Decimal::toFloat', 'toString' => 'php::Decimal::toString'], ]; /** @@ -438,7 +440,7 @@ trait UniversalMethodCall } $receiver = $funcDef->argInfoList[0]; if ($receiver->byRef - || $receiver->type !== CompilerBase::TYPE_OBJECT + || $receiver->type !== Type::OBJECT || !$this->isSameClassName($receiver->declaredClass, $class)) { continue; } @@ -513,7 +515,7 @@ trait UniversalMethodCall continue; } $firstParam = $funcDef->argInfoList[0]; - if ($firstParam->type !== CompilerBase::TYPE_VAR) { + if ($firstParam->type !== Type::VAR) { continue; } @@ -564,7 +566,7 @@ trait UniversalMethodCall } $phpType = Reflection::getFunctionReturnType($funcName); - $returnType = $phpType ? ($this->zendTypeMap[$phpType] ?? CompilerBase::TYPE_VAR) : CompilerBase::TYPE_VAR; + $returnType = $phpType ? ($this->zendTypeMap[$phpType] ?? Type::VAR) : Type::VAR; $requiredParams = $ref->getNumberOfRequiredParameters(); $minArgs = max(0, $requiredParams - 1); @@ -594,14 +596,14 @@ trait UniversalMethodCall } $firstParam = $funcDef->argInfoList[0]; // Stream/Box are PHP pseudo-types; their params may be typed or untyped - if ($type === self::TYPE_STREAM || $type === self::TYPE_BOX) { - return $firstParam->byRef || $firstParam->type === self::TYPE_VAR || $firstParam->type === self::TYPE_REF || $firstParam->type === $type; + if ($type === Type::STREAM || $type === Type::BOX) { + return $firstParam->byRef || $firstParam->type === Type::VAR || $firstParam->type === Type::REF || $firstParam->type === $type; } if ($firstParam->byRef) { - return $type === self::TYPE_ARRAY; + return $type === Type::ARRAY; } $paramType = $firstParam->type; - if ($paramType === self::TYPE_VAR) { + if ($paramType === Type::VAR) { return false; } return $paramType === $type; @@ -614,11 +616,11 @@ trait UniversalMethodCall return false; } // Stream pseudo-type: accept untyped or by-reference first params - if ($type === self::TYPE_STREAM) { + if ($type === Type::STREAM) { return true; } if ($param->isPassedByReference()) { - return $type === self::TYPE_ARRAY; + return $type === Type::ARRAY; } $paramType = $param->getType(); if ($paramType === null) { @@ -678,7 +680,7 @@ trait UniversalMethodCall $this->validateUniversalMethodArgs($expr, $method, $def, false); // Evaluate receiver into temp var to avoid double evaluation - $streamVar = $this->addTmpVar(self::TYPE_VAR); + $streamVar = $this->addTmpVar(Type::VAR); $this->context->beforeStmtLines[] = $streamVar . ' = ' . $receiver . ';'; $methodCall = match ($def['handler']) { @@ -688,7 +690,7 @@ trait UniversalMethodCall default => null, }; - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpVar = $this->addTmpVar(Type::VAR); $this->context->beforeStmtLines[] = "{$tmpVar} = {$methodCall};"; return $tmpVar; } @@ -700,11 +702,11 @@ trait UniversalMethodCall protected function wrapUniversalReceiver(string $type, string $expr): string { $convFns = [ - self::TYPE_ARRAY => 'toArray', - self::TYPE_STR => 'toString', - self::TYPE_INT => 'toInt', - self::TYPE_FLOAT => 'toFloat', - self::TYPE_BOOL => 'toBool', + Type::ARRAY => 'toArray', + Type::STR => 'toString', + Type::INT => 'toInt', + Type::FLOAT => 'toFloat', + Type::BOOL => 'toBool', ]; if (isset($convFns[$type])) { return 'php::' . $convFns[$type] . '(' . $expr . ')'; @@ -898,8 +900,8 @@ trait UniversalMethodCall protected function genUniversalPhpFnRef(string $receiver, string $phpFunc, array $args, string $returnType): string { - $tmpRef = $this->addTmpVar(self::TYPE_REF); - $tmpVar = $this->addTmpVar(self::TYPE_VAR); + $tmpRef = $this->addTmpVar(Type::REF); + $tmpVar = $this->addTmpVar(Type::VAR); $argExprs = ['&' . $tmpRef]; foreach ($args as $arg) { $argExprs[] = $this->parseExpr($arg->value); diff --git a/src/Preprocessor.php b/src/Preprocessor.php index 03dee1b4..ab08a9b2 100644 --- a/src/Preprocessor.php +++ b/src/Preprocessor.php @@ -69,8 +69,8 @@ class Preprocessor extends CompilerBase protected function genArgumentDeclaration(ArgInfo $argInfo): string { $type = $argInfo->type; - if ($type === self::TYPE_STREAM || $type === self::TYPE_BOX) { - $type = self::TYPE_VAR; + if ($type === Type::STREAM || $type === Type::BOX) { + $type = Type::VAR; } return $type . ' ' . $argInfo->name; } @@ -267,7 +267,7 @@ class Preprocessor extends CompilerBase protected function parseParameterType(Node\Param $param, ArgInfo $argInfo, string $var): string { if ($param->byRef) { - return self::TYPE_REF; + return Type::REF; } $class = ''; $type = $this->parseTypeDecl($param->type, self::DECL_TYPE_OF_PARAM, $class); @@ -367,7 +367,7 @@ class Preprocessor extends CompilerBase } } if ($param->variadic) { - $list[] = self::TYPE_ARRAY . ' ' . $name; + $list[] = Type::ARRAY . ' ' . $name; } else { $list[] = $this->genArgumentDeclaration($argInfo); } @@ -438,7 +438,7 @@ class Preprocessor extends CompilerBase $returnType = $this->parseTypeDecl($v->returnType, self::DECL_TYPE_OF_RETURN, $class); // 构造、析构、克隆方法不能有返回值 if ($this->method and in_array($this->method, ['__construct', '__destruct', '__clone'])) { - $returnType = self::TYPE_VOID; + $returnType = Type::VOID; } $functionDef = new FunctionDef($fnName, $returnType, $this->namespace); @@ -470,13 +470,13 @@ class Preprocessor extends CompilerBase if (count($v->params) != 2) { $this->fatalError($v, 'The parameters of the main function must be `(int $argc, array $argv)`.'); } - if ($returnType !== self::TYPE_VOID) { + if ($returnType !== Type::VOID) { $this->fatalError($v, 'main function must return void'); } - if (!$this->checkArgType($functionDef->argInfoList[0]->type, self::TYPE_INT)) { + if (!$this->checkArgType($functionDef->argInfoList[0]->type, Type::INT)) { $this->fatalError($v, 'The first parameter of the main function must be of type `int`.'); } - if (!$this->checkArgType($functionDef->argInfoList[1]->type, self::TYPE_ARRAY)) { + if (!$this->checkArgType($functionDef->argInfoList[1]->type, Type::ARRAY)) { $this->fatalError($v, 'The second parameter of the main function must be of type `array`.'); } } @@ -648,9 +648,9 @@ class Preprocessor extends CompilerBase $type = $declaredType; if ($type === null) { $type = match ($const->value->getType()) { - 'Expr_Array' => self::TYPE_ARRAY, - 'Scalar_String' => self::TYPE_STR, - default => self::TYPE_VAR, + 'Expr_Array' => Type::ARRAY, + 'Scalar_String' => Type::STR, + default => Type::VAR, }; } $constName = $this->parseIdentifier($const->name); @@ -697,7 +697,7 @@ class Preprocessor extends CompilerBase $arrayInitPlan = null; if ($defaultNode !== null) { if ($defaultNode instanceof Node\Expr\Array_) { - $type = self::TYPE_ARRAY; + $type = Type::ARRAY; $arrayInitPlan = $this->buildLiteralArrayInitPlan($defaultNode); $default = $arrayInitPlan->expr; } else { @@ -868,9 +868,9 @@ class Preprocessor extends CompilerBase $type = $stmt->type ? $this->parseTypeDecl($stmt->type, self::DECL_TYPE_OF_CONST, $class) : match ($const->value->getType()) { - 'Expr_Array' => self::TYPE_ARRAY, - 'Scalar_String' => self::TYPE_STR, - default => self::TYPE_VAR, + 'Expr_Array' => Type::ARRAY, + 'Scalar_String' => Type::STR, + default => Type::VAR, }; $constInfo = $this->parseClassLikeConstant($const, $this->parseModifiers($stmt->flags), $type, $class); $this->interfaceDef->constants[$constName] = $constInfo; diff --git a/src/Resolver/DeclarationSymbolTrait.php b/src/Resolver/DeclarationSymbolTrait.php index 9c9443fe..d2fa02e9 100644 --- a/src/Resolver/DeclarationSymbolTrait.php +++ b/src/Resolver/DeclarationSymbolTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\Resolver; +use TypePhp\Type; + use PhpParser\Node; trait DeclarationSymbolTrait @@ -51,16 +53,16 @@ trait DeclarationSymbolTrait protected function detectStrValueType(mixed $constant): string { if ($this->isIntStr($constant)) { - return self::TYPE_INT; + return Type::INT; } if ($this->isFloatStr($constant)) { - return self::TYPE_FLOAT; + return Type::FLOAT; } if ($this->isBoolStr($constant)) { - return self::TYPE_BOOL; + return Type::BOOL; } - return self::TYPE_VAR; + return Type::VAR; } diff --git a/src/Resolver/MagicMethodDetector.php b/src/Resolver/MagicMethodDetector.php index e8125382..f4644a6d 100644 --- a/src/Resolver/MagicMethodDetector.php +++ b/src/Resolver/MagicMethodDetector.php @@ -8,6 +8,8 @@ namespace TypePhp\Resolver; +use TypePhp\Type; + use TypePhp\Entity\MethodDef; use PhpParser\NodeAbstract; @@ -91,110 +93,110 @@ trait MagicMethodDetector if ($nameLower == '__call' or $nameLower == '__callstatic') { if ($argInfoList[0]->undeclared) { - $argInfoList[0]->type = self::TYPE_STR; - } elseif ($argInfoList[0]->type !== self::TYPE_STR) { + $argInfoList[0]->type = Type::STR; + } elseif ($argInfoList[0]->type !== Type::STR) { $this->fatalError($v, 'Method ' . $methodName . '() must take string as first argument'); } if ($argInfoList[1]->undeclared) { - $argInfoList[1]->type = self::TYPE_ARRAY; - } elseif ($argInfoList[1]->type !== self::TYPE_ARRAY) { + $argInfoList[1]->type = Type::ARRAY; + } elseif ($argInfoList[1]->type !== Type::ARRAY) { $this->fatalError($v, 'Method ' . $methodName . '() must take array as second argument'); } } elseif ($nameLower == '__set') { if ($argInfoList[0]->undeclared) { - $argInfoList[0]->type = self::TYPE_STR; - } elseif ($argInfoList[0]->type !== self::TYPE_STR) { + $argInfoList[0]->type = Type::STR; + } elseif ($argInfoList[0]->type !== Type::STR) { $this->fatalError($v, 'Method ' . $methodName . '() must take string as first argument'); } if ($returnTypeUndeclared) { - $fnDef->returnType = self::TYPE_VOID; - } elseif ($fnDef->returnType !== self::TYPE_VOID) { + $fnDef->returnType = Type::VOID; + } elseif ($fnDef->returnType !== Type::VOID) { $this->fatalError($v, 'Method ' . $methodName . '() must return void'); } } elseif ($nameLower == '__get') { if ($argInfoList[0]->undeclared) { - $argInfoList[0]->type = self::TYPE_STR; - } elseif ($argInfoList[0]->type !== self::TYPE_STR) { + $argInfoList[0]->type = Type::STR; + } elseif ($argInfoList[0]->type !== Type::STR) { $this->fatalError($v, 'Method ' . $methodName . '() must take string as argument'); } } elseif ($nameLower == '__tostring') { if ($returnTypeUndeclared) { - $fnDef->returnType = self::TYPE_STR; - } elseif ($fnDef->returnType !== self::TYPE_STR) { + $fnDef->returnType = Type::STR; + } elseif ($fnDef->returnType !== Type::STR) { $this->fatalError($v, 'Method ' . $methodName . '() must return string'); } } elseif ($nameLower == '__serialize') { if ($returnTypeUndeclared) { - $fnDef->returnType = self::TYPE_ARRAY; - } elseif ($fnDef->returnType !== self::TYPE_ARRAY) { + $fnDef->returnType = Type::ARRAY; + } elseif ($fnDef->returnType !== Type::ARRAY) { $this->fatalError($v, 'Method ' . $methodName . '() must return array'); } } elseif ($nameLower == '__unserialize') { if ($argInfoList[0]->undeclared) { - $argInfoList[0]->type = self::TYPE_ARRAY; - } elseif ($argInfoList[0]->type !== self::TYPE_ARRAY) { + $argInfoList[0]->type = Type::ARRAY; + } elseif ($argInfoList[0]->type !== Type::ARRAY) { $this->fatalError($v, 'Method ' . $methodName . '() must take array as argument'); } if ($returnTypeUndeclared) { - $fnDef->returnType = self::TYPE_VOID; - } elseif ($fnDef->returnType !== self::TYPE_VOID) { + $fnDef->returnType = Type::VOID; + } elseif ($fnDef->returnType !== Type::VOID) { $this->fatalError($v, 'Method ' . $methodName . '() must return void'); } } elseif ($nameLower == '__isset') { if ($argInfoList[0]->undeclared) { - $argInfoList[0]->type = self::TYPE_STR; - } elseif ($argInfoList[0]->type !== self::TYPE_STR) { + $argInfoList[0]->type = Type::STR; + } elseif ($argInfoList[0]->type !== Type::STR) { $this->fatalError($v, 'Method ' . $methodName . '() must take string as argument'); } if ($returnTypeUndeclared) { - $fnDef->returnType = self::TYPE_BOOL; - } elseif ($fnDef->returnType !== self::TYPE_BOOL) { + $fnDef->returnType = Type::BOOL; + } elseif ($fnDef->returnType !== Type::BOOL) { $this->fatalError($v, 'Method ' . $methodName . '() must return bool'); } } elseif ($nameLower == '__unset') { if ($argInfoList[0]->undeclared) { - $argInfoList[0]->type = self::TYPE_STR; - } elseif ($argInfoList[0]->type !== self::TYPE_STR) { + $argInfoList[0]->type = Type::STR; + } elseif ($argInfoList[0]->type !== Type::STR) { $this->fatalError($v, 'Method ' . $methodName . '() must take string as argument'); } if ($returnTypeUndeclared) { - $fnDef->returnType = self::TYPE_VOID; - } elseif ($fnDef->returnType !== self::TYPE_VOID) { + $fnDef->returnType = Type::VOID; + } elseif ($fnDef->returnType !== Type::VOID) { $this->fatalError($v, 'Method ' . $methodName . '() must return void'); } } elseif ($nameLower == '__set_state') { if ($argInfoList[0]->undeclared) { - $argInfoList[0]->type = self::TYPE_ARRAY; - } elseif ($argInfoList[0]->type !== self::TYPE_ARRAY) { + $argInfoList[0]->type = Type::ARRAY; + } elseif ($argInfoList[0]->type !== Type::ARRAY) { $this->fatalError($v, 'Method ' . $methodName . '() must take array as argument'); } if ($returnTypeUndeclared) { - $fnDef->returnType = self::TYPE_OBJECT; - } elseif ($fnDef->returnType !== self::TYPE_OBJECT) { + $fnDef->returnType = Type::OBJECT; + } elseif ($fnDef->returnType !== Type::OBJECT) { $this->fatalError($v, 'Method ' . $methodName . '() must return object'); } } elseif ($nameLower == '__debuginfo') { if ($returnTypeUndeclared) { - $fnDef->returnType = self::TYPE_ARRAY; - } elseif ($fnDef->returnType !== self::TYPE_ARRAY) { + $fnDef->returnType = Type::ARRAY; + } elseif ($fnDef->returnType !== Type::ARRAY) { $this->fatalError($v, 'Method ' . $methodName . '() must return array'); } } elseif ($nameLower == '__sleep') { if ($returnTypeUndeclared) { - $fnDef->returnType = self::TYPE_ARRAY; - } elseif ($fnDef->returnType !== self::TYPE_ARRAY) { + $fnDef->returnType = Type::ARRAY; + } elseif ($fnDef->returnType !== Type::ARRAY) { $this->fatalError($v, 'Method ' . $methodName . '() must return array'); } } elseif ($nameLower == '__wakeup') { if ($returnTypeUndeclared) { - $fnDef->returnType = self::TYPE_VOID; - } elseif ($fnDef->returnType !== self::TYPE_VOID) { + $fnDef->returnType = Type::VOID; + } elseif ($fnDef->returnType !== Type::VOID) { $this->fatalError($v, 'Method ' . $methodName . '() must return void'); } } elseif ($nameLower == '__clone') { if ($returnTypeUndeclared) { - $fnDef->returnType = self::TYPE_VOID; - } elseif ($fnDef->returnType !== self::TYPE_VOID) { + $fnDef->returnType = Type::VOID; + } elseif ($fnDef->returnType !== Type::VOID) { $this->fatalError($v, 'Method ' . $methodName . '() must return void'); } } @@ -203,11 +205,11 @@ trait MagicMethodDetector $list = []; foreach ($fnDef->argInfoList as $argInfo) { if ($argInfo->variadic) { - $list[] = self::TYPE_ARRAY . ' ' . $argInfo->name; + $list[] = Type::ARRAY . ' ' . $argInfo->name; } else { $type = $argInfo->type; - if ($type === self::TYPE_STREAM || $type === self::TYPE_BOX) { - $type = self::TYPE_VAR; + if ($type === Type::STREAM || $type === Type::BOX) { + $type = Type::VAR; } $list[] = $type . ' ' . $argInfo->name; } @@ -217,7 +219,7 @@ trait MagicMethodDetector protected function checkArgType(string $givenType, string $expectType, bool $canBeVar = true): bool { - if ($canBeVar and $givenType == self::TYPE_VAR) { + if ($canBeVar and $givenType == Type::VAR) { return true; } return $givenType == $expectType; diff --git a/src/Resolver/NameResolutionTrait.php b/src/Resolver/NameResolutionTrait.php index 836c4bba..53473da9 100644 --- a/src/Resolver/NameResolutionTrait.php +++ b/src/Resolver/NameResolutionTrait.php @@ -8,6 +8,8 @@ namespace TypePhp\Resolver; +use TypePhp\Type; + use PhpParser\Node; use PhpParser\Node\IntersectionType; use PhpParser\Node\NullableType; @@ -131,11 +133,11 @@ trait NameResolutionTrait { // 未定义类型视为 var (mixed, any) if ($type === null) { - return self::TYPE_VAR; + return Type::VAR; } if ($type instanceof UnionType || $type instanceof NullableType || $type instanceof IntersectionType) { // 复杂类型静态阶段统一按 mixed/var 处理,运行时再由 typeCheck 兜底。 - return self::TYPE_VAR; + return Type::VAR; } else { $typeName = $this->parseIdentifier($type); $typeNameLower = strtolower($typeName); @@ -162,7 +164,7 @@ trait NameResolutionTrait if ($class and $this->classDef and $this->classDef->trait) { $type->name = $class; } - return self::TYPE_OBJECT; + return Type::OBJECT; } } } diff --git a/src/Resolver/PropertyAssignTypeInfo.php b/src/Resolver/PropertyAssignTypeInfo.php index 9c3ae4f2..2de9d879 100644 --- a/src/Resolver/PropertyAssignTypeInfo.php +++ b/src/Resolver/PropertyAssignTypeInfo.php @@ -8,7 +8,8 @@ namespace TypePhp\Resolver; -use TypePhp\CompilerBase; +use TypePhp\Type; + use TypePhp\Entity\PropertyDef; final class PropertyAssignTypeInfo @@ -16,11 +17,11 @@ final class PropertyAssignTypeInfo public function getFixedDefaultValue(PropertyDef $def): ?string { return match ($def->type) { - CompilerBase::TYPE_INT => $def->default ?? '0', - CompilerBase::TYPE_FLOAT => $def->default ?? '0.0', - CompilerBase::TYPE_BOOL => $def->default ?? 'false', - CompilerBase::TYPE_STR => $def->default ?? CompilerBase::TYPE_STR . '()', - CompilerBase::TYPE_ARRAY => $def->default ?? CompilerBase::TYPE_ARRAY . '{}', + Type::INT => $def->default ?? '0', + Type::FLOAT => $def->default ?? '0.0', + Type::BOOL => $def->default ?? 'false', + Type::STR => $def->default ?? Type::STR . '()', + Type::ARRAY => $def->default ?? Type::ARRAY . '{}', default => null, }; } @@ -28,11 +29,11 @@ final class PropertyAssignTypeInfo public function isFixed(PropertyDef $def): bool { return in_array($def->type, [ - CompilerBase::TYPE_INT, - CompilerBase::TYPE_FLOAT, - CompilerBase::TYPE_BOOL, - CompilerBase::TYPE_STR, - CompilerBase::TYPE_ARRAY, + Type::INT, + Type::FLOAT, + Type::BOOL, + Type::STR, + Type::ARRAY, ], true) && !$def->nullable; } @@ -46,17 +47,17 @@ final class PropertyAssignTypeInfo $check[] = ['kind' => 'isNull']; } $scalarCheck = match ($def->type) { - CompilerBase::TYPE_INT => [['kind' => 'isInt']], - CompilerBase::TYPE_FLOAT => [['kind' => 'isFloat'], ['kind' => 'isInt']], - CompilerBase::TYPE_BOOL => [['kind' => 'isBool']], - CompilerBase::TYPE_STR => [['kind' => 'isString']], - CompilerBase::TYPE_ARRAY => [['kind' => 'isArray']], + Type::INT => [['kind' => 'isInt']], + Type::FLOAT => [['kind' => 'isFloat'], ['kind' => 'isInt']], + Type::BOOL => [['kind' => 'isBool']], + Type::STR => [['kind' => 'isString']], + Type::ARRAY => [['kind' => 'isArray']], default => null, }; if ($scalarCheck !== null) { return array_merge($check, $scalarCheck); } - if ($def->type !== CompilerBase::TYPE_OBJECT || $def->class === '') { + if ($def->type !== Type::OBJECT || $def->class === '') { return []; } @@ -73,12 +74,12 @@ final class PropertyAssignTypeInfo return ($def->nullable ? '?' : '') . $def->class; } return match ($def->type) { - CompilerBase::TYPE_INT => 'int', - CompilerBase::TYPE_FLOAT => 'float', - CompilerBase::TYPE_BOOL => 'bool', - CompilerBase::TYPE_STR => 'string', - CompilerBase::TYPE_ARRAY => 'array', - CompilerBase::TYPE_OBJECT => 'object', + Type::INT => 'int', + Type::FLOAT => 'float', + Type::BOOL => 'bool', + Type::STR => 'string', + Type::ARRAY => 'array', + Type::OBJECT => 'object', default => $def->type, }; } diff --git a/src/Translator.php b/src/Translator.php index 2ae78ab8..146a5473 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -649,12 +649,12 @@ class Translator extends Preprocessor $lines[] = '#include '; $lines[] = PHP_EOL; foreach ($this->globalVars as $name => $type) { - $lines[] = 'extern THREAD_LOCAL ' . self::TYPE_VAR . ' ' . $this->escapeGlobalVar($name) . ';'; + $lines[] = 'extern THREAD_LOCAL ' . Type::VAR . ' ' . $this->escapeGlobalVar($name) . ';'; } if ($this->literalStrings) { $literalStringsCount = count($this->literalStrings); - $lines[] = 'extern ' . self::TYPE_STR . ' ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL; + $lines[] = 'extern ' . Type::STR . ' ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL; } // 确保数组大小至少为 1,避免 C/C++ 编译错误 @@ -669,9 +669,9 @@ class Translator extends Preprocessor foreach ($this->getClassLikesWithConstants() as $classDef) { foreach ($classDef->constants as $constant) { - if ($constant->type === self::TYPE_ARRAY) { + if ($constant->type === Type::ARRAY) { $constName = self::PREFIX . $this->getNativeName($constant->name, $classDef->namespace, $classDef->name); - $lines[] = 'extern ' . self::TYPE_VAR . ' ' . $constName . ';' . PHP_EOL; + $lines[] = 'extern ' . Type::VAR . ' ' . $constName . ';' . PHP_EOL; } } } @@ -713,7 +713,7 @@ class Translator extends Preprocessor $code .= "// global vars \n"; foreach ($this->globalVars as $name => $type) { - $code .= 'THREAD_LOCAL ' . self::TYPE_VAR . ' ' . $this->escapeGlobalVar($name) . ';' . PHP_EOL; + $code .= 'THREAD_LOCAL ' . Type::VAR . ' ' . $this->escapeGlobalVar($name) . ';' . PHP_EOL; } $code .= "// class register functions \n"; @@ -767,9 +767,9 @@ CODE; $code .= "// literal strings \n"; if ($this->literalStrings) { - $code .= self::TYPE_STR . ' ' . self::LITERAL_STRINGS . '[] = {' . PHP_EOL; + $code .= Type::STR . ' ' . self::LITERAL_STRINGS . '[] = {' . PHP_EOL; foreach ($this->literalStrings as $str => $index) { - $code .= self::TYPE_STR . '{ZEND_STRL("' . $this->escapeString($str) . '"), true}, // [' . $index . ']' . PHP_EOL; + $code .= Type::STR . '{ZEND_STRL("' . $this->escapeString($str) . '"), true}, // [' . $index . ']' . PHP_EOL; } $code .= '};' . PHP_EOL . PHP_EOL; } else { @@ -788,9 +788,9 @@ CODE; $code .= 'static zend_object_handlers property_handlers_' . $classDef->getNamespacedName() . ";\n"; } foreach ($classDef->constants as $constant) { - if ($constant->type === self::TYPE_ARRAY) { + if ($constant->type === Type::ARRAY) { $constName = self::PREFIX . $this->getNativeName($constant->name, $classDef->namespace, $classDef->name); - $code .= self::TYPE_VAR . ' ' . $constName . ";\n"; + $code .= Type::VAR . ' ' . $constName . ";\n"; } } } @@ -880,7 +880,7 @@ CODE; } } foreach ($this->constants as $name => $const) { - if ($const->type !== self::TYPE_VAR) { + if ($const->type !== Type::VAR) { continue; } $code .= $name . '.unset();' . PHP_EOL; @@ -889,7 +889,7 @@ CODE; $code .= '// class array constants' . PHP_EOL; foreach ($this->getClassLikesWithConstants() as $classDef) { foreach ($classDef->constants as $constant) { - if ($constant->type === self::TYPE_ARRAY) { + if ($constant->type === Type::ARRAY) { $constName = self::PREFIX . $this->getNativeName($constant->name, $classDef->namespace, $classDef->name); $code .= $constName . ".unset();\n"; @@ -904,7 +904,7 @@ CODE; foreach ($this->symbols->classes() as $className => $classDef) { $ownConstNames = []; foreach ($classDef->constants as $constant) { - if ($constant->type === self::TYPE_ARRAY) { + if ($constant->type === Type::ARRAY) { $ownConstNames[$constant->name] = true; } } @@ -913,7 +913,7 @@ CODE; while ($parentName && $this->symbols->hasClass($parentName)) { $parentDef = $this->symbols->class($parentName); foreach ($parentDef->constants as $constant) { - if ($constant->type === self::TYPE_ARRAY && !isset($ownConstNames[$constant->name])) { + if ($constant->type === Type::ARRAY && !isset($ownConstNames[$constant->name])) { $ownConstNames[$constant->name] = true; $classNameStr = $this->genCharPtr($classDef->getNamespacedName(false), true); $classConstStr = $this->genCharPtr($constant->name); @@ -929,7 +929,7 @@ CODE; } $interfaceDef = $this->getInterface($interfaceName); foreach ($interfaceDef->constants as $constant) { - if ($constant->type === self::TYPE_ARRAY && !isset($ownConstNames[$constant->name])) { + if ($constant->type === Type::ARRAY && !isset($ownConstNames[$constant->name])) { $ownConstNames[$constant->name] = true; $classNameStr = $this->genCharPtr($classDef->getNamespacedName(false), true); $classConstStr = $this->genCharPtr($constant->name); @@ -1427,21 +1427,21 @@ CODE; // 函数的默认值可能会使用字符串字面量,需要提前声明 if ($this->literalStrings) { $literalStringsCount = count($this->literalStrings); - $code .= 'extern ' . self::TYPE_STR . ' ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL; + $code .= 'extern ' . Type::STR . ' ' . self::LITERAL_STRINGS . '[' . $literalStringsCount . '];' . PHP_EOL; } $code .= $this->genDefaultArgumentHelpers(); foreach ($this->symbols->functions() as $name => $func) { - $code .= 'extern ' . ($func->returnsByRef ? self::TYPE_REF : $func->returnType) . ' ' . self::PREFIX . $name . '('; + $code .= 'extern ' . ($func->returnsByRef ? Type::REF : $func->returnType) . ' ' . self::PREFIX . $name . '('; $list = []; if ($func->method) { - $list[] = self::TYPE_OBJECT . ' &this_'; + $list[] = Type::OBJECT . ' &this_'; } $argInfoList = $func->argInfoList; if ($argInfoList) { foreach ($argInfoList as $argInfo) { if ($argInfo->variadic) { - $arg = self::TYPE_ARRAY . ' ' . $argInfo->name . ' = {}'; + $arg = Type::ARRAY . ' ' . $argInfo->name . ' = {}'; } else { $arg = $this->genArgumentDeclaration($argInfo); if ($argInfo->default && !$this->isConstructorNativeFunction($func)) { @@ -1599,7 +1599,7 @@ CODE; $code = ''; foreach ($this->getClassLikesWithConstants() as $classDef) { foreach ($classDef->constants as $constant) { - if ($constant->type === self::TYPE_ARRAY) { + if ($constant->type === Type::ARRAY) { $constName = self::PREFIX . $this->getNativeName($constant->name, $classDef->namespace, $classDef->name); $code .= "do {\n"; $code .= $constant->arrayExpr; @@ -1616,7 +1616,7 @@ CODE; foreach ($this->symbols->classes() as $className => $classDef) { $ownConstNames = []; foreach ($classDef->constants as $constant) { - if ($constant->type === self::TYPE_ARRAY) { + if ($constant->type === Type::ARRAY) { $ownConstNames[$constant->name] = true; } } @@ -1625,7 +1625,7 @@ CODE; while ($parentName && $this->symbols->hasClass($parentName)) { $parentDef = $this->symbols->class($parentName); foreach ($parentDef->constants as $constant) { - if ($constant->type === self::TYPE_ARRAY && !isset($ownConstNames[$constant->name])) { + if ($constant->type === Type::ARRAY && !isset($ownConstNames[$constant->name])) { $ownConstNames[$constant->name] = true; $constName = self::PREFIX . $this->getNativeName($constant->name, $parentDef->namespace, $parentDef->name); $classNameStr = $this->genCharPtr($classDef->getNamespacedName(false), true); @@ -1642,7 +1642,7 @@ CODE; } $interfaceDef = $this->getInterface($interfaceName); foreach ($interfaceDef->constants as $constant) { - if ($constant->type === self::TYPE_ARRAY && !isset($ownConstNames[$constant->name])) { + if ($constant->type === Type::ARRAY && !isset($ownConstNames[$constant->name])) { $ownConstNames[$constant->name] = true; $constName = self::PREFIX . $this->getNativeName($constant->name, $interfaceDef->namespace, $interfaceDef->name); $classNameStr = $this->genCharPtr($classDef->getNamespacedName(false), true); @@ -2584,7 +2584,7 @@ CODE; foreach ($functionDef->argInfoList as $k => $argInfo) { $var = 'arg_' . $argInfo->name; if ($argInfo->variadic) { - $cppCode .= $this->getIndent() . self::TYPE_ARRAY . ' ' . $var . ';' . PHP_EOL; + $cppCode .= $this->getIndent() . Type::ARRAY . ' ' . $var . ';' . PHP_EOL; $cppCode .= $this->getIndent() . 'for (uint32_t i = ' . $k . '; i < php::getCallArgNum(); i++) {' . PHP_EOL; $this->indentLevel++; $cppCode .= $this->getIndent() . $var . '.append(php::getCallArg(i));' . PHP_EOL; @@ -2608,7 +2608,7 @@ CODE; } $cppType = $this->getDefaultArgumentType($argInfo); $declaredClass = $argInfo->declaredClass ?: $argInfo->class; - if ($argInfo->type === self::TYPE_OBJECT && $declaredClass !== '') { + if ($argInfo->type === Type::OBJECT && $declaredClass !== '') { $expr = $this->convertObjectExpr($argExpr, $this->getClassEntryPtr($declaredClass)); } else { $expr = $this->convertExprFromType($argInfo->type, $argExpr); @@ -2624,7 +2624,7 @@ CODE; $callParams = $functionDef->argInfoList ? rtrim($callParams, ',') : ''; } - if ($functionDef->returnType !== self::TYPE_VOID) { + if ($functionDef->returnType !== Type::VOID) { $cppCode .= $this->getIndent() . 'auto retval = ' . $fn . '(' . $callParams . ');' . PHP_EOL; $cppCode .= $this->getIndent() . 'php::move(retval, return_value);' . PHP_EOL; if (!$functionDef->returnsByRef) { @@ -2662,7 +2662,7 @@ CODE; { $name = $classDef->getNamespacedName(); $cppCode = 'ZEND_METHOD(' . $name . ', ' . $methodDef->name . '){' . PHP_EOL; - $cppCode .= $this->getIndent() . self::TYPE_OBJECT . ' this_(&execute_data->This);' . PHP_EOL; + $cppCode .= $this->getIndent() . Type::OBJECT . ' this_(&execute_data->This);' . PHP_EOL; $fn = self::PREFIX . $this->getNativeMethodName($classDef, $methodDef); $cppCode .= $this->genWrapperFunctionArgs($fn, $methodDef->functionDef, $classDef->getNamespacedName(false) . '::' . $methodDef->name); @@ -2690,7 +2690,7 @@ CODE; if ($classDef instanceof ClassDef) { $arrayPropCount = 0; foreach ($classDef->properties as $property) { - if ($property->type === self::TYPE_ARRAY && $property->arrayInitPlan && $property->default && !$property->isStatic()) { + if ($property->type === Type::ARRAY && $property->arrayInitPlan && $property->default && !$property->isStatic()) { $arrayPropCount++; } } @@ -2800,10 +2800,10 @@ CODE; } if ($this->class) { - $this->addArgument('this_', self::TYPE_OBJECT); + $this->addArgument('this_', Type::OBJECT); } foreach ($this->functionDef->argInfoList as $argInfo) { - $this->addArgument($argInfo->name, $argInfo->variadic ? self::TYPE_ARRAY : $argInfo->type); + $this->addArgument($argInfo->name, $argInfo->variadic ? Type::ARRAY : $argInfo->type); if (!$argInfo->variadic and $argInfo->declaredClass) { $this->addObject($argInfo->name, $argInfo->declaredClass); } @@ -2853,10 +2853,10 @@ CODE; $stmts = $this->genReturnCode(); } - $cppReturnType = $this->functionDef->returnsByRef ? self::TYPE_REF : $this->getReturnType(); + $cppReturnType = $this->functionDef->returnsByRef ? Type::REF : $this->getReturnType(); $functionDeclCode = $cppReturnType . ' ' . self::PREFIX . $name . '('; if ($this->class) { - $functionDeclCode .= self::TYPE_OBJECT . ' &this_'; + $functionDeclCode .= Type::OBJECT . ' &this_'; if ($this->functionDef->params) { $functionDeclCode .= ', '; } @@ -3043,13 +3043,13 @@ CODE; if ($parentFuncDef->returnTypeCheck || $childFuncDef->returnTypeCheck) { return $parentFuncDef->returnTypeStr === $childFuncDef->returnTypeStr; } - if ($parentFuncDef->returnType === self::TYPE_VAR) { + if ($parentFuncDef->returnType === Type::VAR) { return true; } if ($childFuncDef->returnType !== $parentFuncDef->returnType) { return false; } - if ($parentFuncDef->returnType !== self::TYPE_OBJECT) { + if ($parentFuncDef->returnType !== Type::OBJECT) { return true; } if ($childFuncDef->returnClass === $parentFuncDef->returnClass) { @@ -3084,7 +3084,7 @@ CODE; if ($childArg->type !== $parentArg->type) { return false; } - if ($parentArg->type !== self::TYPE_OBJECT) { + if ($parentArg->type !== Type::OBJECT) { return true; } if ($childArg->class === $parentArg->class) { @@ -3108,13 +3108,13 @@ CODE; } return match ($arg->type) { - self::TYPE_INT => [['kind' => 'isInt']], - self::TYPE_FLOAT => [['kind' => 'isFloat']], - self::TYPE_BOOL => [['kind' => 'isBool']], - self::TYPE_STR => [['kind' => 'isString']], - self::TYPE_ARRAY => [['kind' => 'isArray']], - self::TYPE_RESOURCE => [['kind' => 'isResource']], - self::TYPE_OBJECT => $arg->class + Type::INT => [['kind' => 'isInt']], + Type::FLOAT => [['kind' => 'isFloat']], + Type::BOOL => [['kind' => 'isBool']], + Type::STR => [['kind' => 'isString']], + Type::ARRAY => [['kind' => 'isArray']], + Type::RESOURCE => [['kind' => 'isResource']], + Type::OBJECT => $arg->class ? [['kind' => 'instanceof', 'class' => $arg->class]] : [['kind' => 'isObject']], default => null, @@ -3484,10 +3484,10 @@ CODE; } $argv = implode(', ', $argList); - $cppReturnType = $methodDef->functionDef->returnsByRef ? self::TYPE_REF : $methodDef->getReturnType(); + $cppReturnType = $methodDef->functionDef->returnsByRef ? Type::REF : $methodDef->getReturnType(); $code = $cppReturnType . ' ' . self::PREFIX . $classMethodNativeName . '('; if ($this->class) { - $code .= self::TYPE_OBJECT . ' &this_'; + $code .= Type::OBJECT . ' &this_'; if ($methodDef->functionDef->params) { $code .= ', '; } @@ -3499,7 +3499,7 @@ CODE; $code .= '{' . PHP_EOL; $this->indentLevel++; $methodCall = self::PREFIX . $traitMethodNativeName . '(' . $argv . ')'; - if ($cppReturnType !== self::TYPE_VOID) { + if ($cppReturnType !== Type::VOID) { $methodCall = 'return ' . $methodCall; } $code .= $this->getIndent() . $methodCall . ';' . PHP_EOL; @@ -3529,16 +3529,16 @@ CODE; { $obj = $objectExpr ?? $this->parseIdentifier($node->expr); $iterableVar = $this->genTmpVarName(); - $this->addLocalVar($iterableVar, self::TYPE_VAR); + $this->addLocalVar($iterableVar, Type::VAR); $iteratorObj = $this->genTmpVarName(); - $this->addLocalVar($iteratorObj, self::TYPE_OBJECT); + $this->addLocalVar($iteratorObj, Type::OBJECT); $aggregateObj = $this->genTmpVarName(); - $this->addLocalVar($aggregateObj, self::TYPE_OBJECT); + $this->addLocalVar($aggregateObj, Type::OBJECT); $tmpArrayVar = $this->genTmpVarName(); - $this->addLocalVar($tmpArrayVar, self::TYPE_ARRAY); + $this->addLocalVar($tmpArrayVar, Type::ARRAY); $IteratorAggregateCe = $this->getClassEntryPtr('IteratorAggregate'); $IteratorCe = $this->getClassEntryPtr('Iterator'); diff --git a/src/Type.php b/src/Type.php new file mode 100644 index 00000000..5524aa31 --- /dev/null +++ b/src/Type.php @@ -0,0 +1,27 @@ +detectTypeOfExpr($value) === self::TYPE_VAR && !$this->isNullExpr($value)) { + if ($this->detectTypeOfExpr($value) === Type::VAR && !$this->isNullExpr($value)) { return self::COMPOSITE_TYPE_UNKNOWN; } @@ -77,19 +79,19 @@ trait CompositeTypeCheckerTrait $type = $this->detectTypeOfExpr($value); return match ($kind) { - 'isInt' => $this->exactCompositeTypeRelation($type, self::TYPE_INT), + 'isInt' => $this->exactCompositeTypeRelation($type, Type::INT), // PHP permits int -> float widening. It is compatible but still // needs conversion, so retain the runtime normalization path. - 'isFloat' => $type === self::TYPE_INT + 'isFloat' => $type === Type::INT ? self::COMPOSITE_TYPE_UNKNOWN - : $this->exactCompositeTypeRelation($type, self::TYPE_FLOAT), - 'isBool' => $this->exactCompositeTypeRelation($type, self::TYPE_BOOL), - 'isString' => $this->exactCompositeTypeRelation($type, self::TYPE_STR), - 'isArray' => $this->exactCompositeTypeRelation($type, self::TYPE_ARRAY), - 'isObject' => $this->exactCompositeTypeRelation($type, self::TYPE_OBJECT), + : $this->exactCompositeTypeRelation($type, Type::FLOAT), + 'isBool' => $this->exactCompositeTypeRelation($type, Type::BOOL), + 'isString' => $this->exactCompositeTypeRelation($type, Type::STR), + 'isArray' => $this->exactCompositeTypeRelation($type, Type::ARRAY), + 'isObject' => $this->exactCompositeTypeRelation($type, Type::OBJECT), 'isTrue' => $this->compositeLiteralBoolRelation($value, true), 'isFalse' => $this->compositeLiteralBoolRelation($value, false), - 'isResource' => $this->exactCompositeTypeRelation($type, self::TYPE_RESOURCE), + 'isResource' => $this->exactCompositeTypeRelation($type, Type::RESOURCE), 'callable' => $this->compositeCallableRelation($value, $type), 'iterable' => $this->compositeIterableRelation($value, $type), 'instanceof' => $this->compositeObjectEntryRelation($value, $entry), @@ -108,14 +110,14 @@ trait CompositeTypeCheckerTrait $actual = strcasecmp($value->name->toString(), 'true') === 0; return $actual === $expected ? self::COMPOSITE_TYPE_MATCH : self::COMPOSITE_TYPE_MISMATCH; } - return $this->detectTypeOfExpr($value) === self::TYPE_BOOL + return $this->detectTypeOfExpr($value) === Type::BOOL ? self::COMPOSITE_TYPE_UNKNOWN : self::COMPOSITE_TYPE_MISMATCH; } protected function compositeCallableRelation(NodeAbstract $value, string $type): int { - if ($type === self::TYPE_STR || $type === self::TYPE_ARRAY || $type === self::TYPE_OBJECT) { + if ($type === Type::STR || $type === Type::ARRAY || $type === Type::OBJECT) { return self::COMPOSITE_TYPE_UNKNOWN; } return self::COMPOSITE_TYPE_MISMATCH; @@ -123,10 +125,10 @@ trait CompositeTypeCheckerTrait protected function compositeIterableRelation(NodeAbstract $value, string $type): int { - if ($type === self::TYPE_ARRAY) { + if ($type === Type::ARRAY) { return self::COMPOSITE_TYPE_MATCH; } - if ($type !== self::TYPE_OBJECT) { + if ($type !== Type::OBJECT) { return self::COMPOSITE_TYPE_MISMATCH; } return $this->compositeObjectTypeRelation($value, 'Traversable'); @@ -134,7 +136,7 @@ trait CompositeTypeCheckerTrait protected function compositeObjectEntryRelation(NodeAbstract $value, array $entry): int { - if ($this->detectTypeOfExpr($value) !== self::TYPE_OBJECT) { + if ($this->detectTypeOfExpr($value) !== Type::OBJECT) { return self::COMPOSITE_TYPE_MISMATCH; } @@ -182,12 +184,12 @@ trait CompositeTypeCheckerTrait } $type = $this->detectTypeOfExpr($expr); return match ($type) { - self::TYPE_INT => 'int', - self::TYPE_FLOAT => 'float', - self::TYPE_BOOL => 'bool', - self::TYPE_STR => 'string', - self::TYPE_ARRAY => 'array', - self::TYPE_OBJECT => 'object', + Type::INT => 'int', + Type::FLOAT => 'float', + Type::BOOL => 'bool', + Type::STR => 'string', + Type::ARRAY => 'array', + Type::OBJECT => 'object', default => 'mixed', }; } diff --git a/src/TypeSystem/NativeTypeCompatibilityTrait.php b/src/TypeSystem/NativeTypeCompatibilityTrait.php index b9356309..1d08660c 100644 --- a/src/TypeSystem/NativeTypeCompatibilityTrait.php +++ b/src/TypeSystem/NativeTypeCompatibilityTrait.php @@ -7,6 +7,8 @@ namespace TypePhp\TypeSystem; +use TypePhp\Type; + use PhpParser\Node; use TypePhp\Entity\ArgInfo; @@ -15,8 +17,8 @@ trait NativeTypeCompatibilityTrait protected function getReturnType(): string { $type = $this->functionDef->returnType; - if ($type === self::TYPE_STREAM) { - return self::TYPE_VAR; + if ($type === Type::STREAM) { + return Type::VAR; } return $type; } @@ -169,7 +171,7 @@ trait NativeTypeCompatibilityTrait $var = $this->parseVariable($arg->value); // 若参数是引用类型,可以传入未定义变量,将立即创建变量作为引用 if (!$this->hasLocalVar($var)) { - $this->addLocalVar($var, self::TYPE_VAR); + $this->addLocalVar($var, Type::VAR); } } return $this->convertToRef($arg->value); @@ -180,14 +182,14 @@ trait NativeTypeCompatibilityTrait $this->checkVarAssignExpr($arg, $argInfo->type, $type); - if ($argInfo->type === self::TYPE_VAR && $this->isVarExpr($arg->value)) { + if ($argInfo->type === Type::VAR && $this->isVarExpr($arg->value)) { $varName = $this->parseIdentifier($arg->value); if ($this->isStdContainer($varName)) { return $varName; } } - if ($argInfo->type === self::TYPE_OBJECT) { + if ($argInfo->type === Type::OBJECT) { $declaredClass = $argInfo->declaredClass ?: $argInfo->class; if ($declaredClass !== '') { $class = $this->detectDeclaredClassOfExpr($arg->value); @@ -197,7 +199,7 @@ trait NativeTypeCompatibilityTrait // 如果无法证明,但右值是已知 concrete object,说明一定不兼容,直接编译期 fatal; // 其他动态/外部库/any 场景保留 php::toObject() 作为运行时兜底。 if ($this->isObjectClassStaticallyAssignableTo($class, $declaredClass)) { - return $type === self::TYPE_OBJECT ? $expr : $this->convertObjectExpr($expr); + return $type === Type::OBJECT ? $expr : $this->convertObjectExpr($expr); } if ($this->isKnownConcreteObjectExpr($arg->value, $class)) { $argName = $argInfo->phpName ?: $this->unescapeVarName($argInfo->name); @@ -206,7 +208,7 @@ trait NativeTypeCompatibilityTrait } return $this->convertObjectExpr($expr, $this->getClassEntryPtr($declaredClass)); } - return $type === self::TYPE_OBJECT ? $expr : $this->convertObjectExpr($expr); + return $type === Type::OBJECT ? $expr : $this->convertObjectExpr($expr); } return $this->convertExprType($expr, $argInfo->type, $type);