TypePHP 编译器
https://swoole.com/aot/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
8.1 KiB
260 lines
8.1 KiB
<?php
|
|
/**
|
|
* This file is part of TypePHP.
|
|
*
|
|
* @link https://www.swoole.com/
|
|
* @contact service@swoole.com
|
|
*/
|
|
|
|
namespace TypePhp\Parser;
|
|
|
|
use TypePhp\Type;
|
|
|
|
use PhpParser\Node;
|
|
use PhpParser\NodeAbstract;
|
|
|
|
trait TypeConversionTrait
|
|
{
|
|
protected function convertExprToStringByType(string $expr, $type): string
|
|
{
|
|
if ($type === Type::STR) {
|
|
return $expr;
|
|
}
|
|
if ($type === Type::BIGINT) {
|
|
return 'php::BigInt::toString(' . $expr . ')';
|
|
}
|
|
if ($type === Type::BIGFLOAT) {
|
|
return 'php::BigFloat::toString(' . $expr . ')';
|
|
}
|
|
if ($type === Type::DECIMAL) {
|
|
return 'php::Decimal::toString(' . $expr . ')';
|
|
}
|
|
return $this->convertStringExpr($expr);
|
|
}
|
|
|
|
protected function convertIntExpr(string $expr, string $fromType = ''): string
|
|
{
|
|
$bigConversion = match ($fromType) {
|
|
Type::BIGINT => 'php::BigInt::toInt',
|
|
Type::BIGFLOAT => 'php::BigFloat::toInt',
|
|
Type::DECIMAL => 'php::Decimal::toInt',
|
|
default => null,
|
|
};
|
|
if ($bigConversion !== null) {
|
|
return $bigConversion . '(' . $expr . ')';
|
|
}
|
|
if (!$this->isClosedExpr($expr, 'php::toInt')) {
|
|
return 'php::toInt(' . $expr . ')';
|
|
}
|
|
|
|
return $expr;
|
|
}
|
|
|
|
protected function convertFloatExpr(string $expr, string $fromType = ''): string
|
|
{
|
|
$bigConversion = match ($fromType) {
|
|
Type::BIGINT => 'php::BigInt::toFloat',
|
|
Type::BIGFLOAT => 'php::BigFloat::toFloat',
|
|
Type::DECIMAL => 'php::Decimal::toFloat',
|
|
default => null,
|
|
};
|
|
if ($bigConversion !== null) {
|
|
return $bigConversion . '(' . $expr . ')';
|
|
}
|
|
if (!$this->isClosedExpr($expr, 'php::toFloat')) {
|
|
return 'php::toFloat(' . $expr . ')';
|
|
}
|
|
|
|
return $expr;
|
|
}
|
|
|
|
protected function convertDecimalExpr(string $expr, string $fromType = '', ?NodeAbstract $node = null): string
|
|
{
|
|
if ($fromType === Type::FLOAT) {
|
|
if ($node instanceof Node\Scalar\Float_) {
|
|
$rawValue = $node->getAttribute('rawValue');
|
|
$clean = $rawValue !== null ? $this->stripNumericUnderscores($rawValue) : (string) $node->value;
|
|
return 'php::toDecimal(' . $this->getLiteralString($clean) . ')';
|
|
}
|
|
$this->fatalError($node, 'Cannot convert float expression to Decimal, use a literal value or string instead');
|
|
}
|
|
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 === Type::INT) {
|
|
return 'php::toDecimal(' . $expr . ')';
|
|
}
|
|
if ($fromType === Type::BIGINT) {
|
|
return 'php::toDecimal(php::BigInt::toString(' . $expr . '))';
|
|
}
|
|
return $expr;
|
|
}
|
|
|
|
protected function convertBigIntExpr(string $expr, string $fromType = ''): string
|
|
{
|
|
if ($fromType === Type::INT) {
|
|
return 'php::toBigInt(' . $expr . ')';
|
|
}
|
|
if ($fromType === Type::FLOAT) {
|
|
$this->error('Cannot convert float to BigInt, use string or int instead');
|
|
}
|
|
if ($fromType === Type::STR) {
|
|
return 'php::toBigInt(php::toString(' . $expr . '))';
|
|
}
|
|
return $expr;
|
|
}
|
|
|
|
protected function convertBigFloatExpr(string $expr, string $fromType = ''): string
|
|
{
|
|
if ($fromType === Type::INT) {
|
|
return 'php::toBigFloat(' . $expr . ')';
|
|
}
|
|
if ($fromType === Type::FLOAT) {
|
|
return 'php::toBigFloat(' . $expr . ')';
|
|
}
|
|
if ($fromType === Type::STR) {
|
|
return 'php::toBigFloat(php::toString(' . $expr . '))';
|
|
}
|
|
if ($fromType === Type::BIGINT) {
|
|
return 'php::BigFloat::newInstance(php::BigInt::toString(' . $expr . '))';
|
|
}
|
|
if ($fromType === Type::DECIMAL) {
|
|
return 'php::BigFloat::newInstance(php::Decimal::toString(' . $expr . '))';
|
|
}
|
|
return $expr;
|
|
}
|
|
|
|
protected function convertStringExpr(string $expr): string
|
|
{
|
|
if (preg_match('/^_literal_strings\[\d+\]$/', $expr) === 1) {
|
|
return $expr;
|
|
}
|
|
if (!$this->isClosedExpr($expr, 'php::toString')) {
|
|
return 'php::toString(' . $expr . ')';
|
|
}
|
|
|
|
return $expr;
|
|
}
|
|
|
|
protected function convertObjectExpr(string $expr, string $class = ''): string
|
|
{
|
|
if (!$this->isClosedExpr($expr, 'php::toObject')) {
|
|
if ($class === '') {
|
|
return 'php::toObject(' . $expr . ')';
|
|
}
|
|
return 'php::toObject(' . $expr . ', ' . $class . ')';
|
|
}
|
|
|
|
return $expr;
|
|
}
|
|
|
|
protected function convertArrayExpr(string $expr): string
|
|
{
|
|
if (!$this->isClosedExpr($expr, 'php::toArray')) {
|
|
return 'php::toArray(' . $expr . ')';
|
|
}
|
|
|
|
return $expr;
|
|
}
|
|
|
|
protected function convertBoolExpr(string $expr, string $fromType = ''): string
|
|
{
|
|
$bigConversion = match ($fromType) {
|
|
Type::BIGINT => 'php::BigInt::toBool',
|
|
Type::BIGFLOAT => 'php::BigFloat::toBool',
|
|
Type::DECIMAL => 'php::Decimal::toBool',
|
|
default => null,
|
|
};
|
|
if ($bigConversion !== null) {
|
|
return $bigConversion . '(' . $expr . ')';
|
|
}
|
|
if (!$this->isClosedExpr($expr, 'php::toBool')) {
|
|
return 'php::toBool(' . $expr . ')';
|
|
}
|
|
|
|
return $expr;
|
|
}
|
|
|
|
protected function convertConditionExpr(NodeAbstract $node, string $expr): string
|
|
{
|
|
$pythonBool = $this->convertPythonObjectToBool($node, $expr);
|
|
if ($pythonBool !== null) {
|
|
return $pythonBool;
|
|
}
|
|
$type = $this->detectTypeOfExpr($node);
|
|
return $this->convertBoolExpr($expr, $type);
|
|
}
|
|
|
|
protected function convertExprType(string $expr, $leftType, $rightType): string
|
|
{
|
|
if ($leftType === Type::FLOAT or $rightType === Type::FLOAT) {
|
|
return $this->convertFloatExpr($expr);
|
|
}
|
|
if ($leftType === Type::INT or $rightType === Type::INT) {
|
|
return $this->convertIntExpr($expr);
|
|
}
|
|
if ($leftType === Type::BOOL or $rightType === Type::BOOL) {
|
|
return $this->convertBoolExpr($expr);
|
|
}
|
|
|
|
return $expr;
|
|
}
|
|
|
|
protected function getNativeType(string $type): string
|
|
{
|
|
if ($type === Type::INT && $this->bigintTypes) {
|
|
return Type::BIGINT;
|
|
}
|
|
if ($type === Type::FLOAT && $this->decimalTypes) {
|
|
return Type::DECIMAL;
|
|
}
|
|
return $this->nativeTypes ? $type : Type::VAR;
|
|
}
|
|
|
|
protected function convertExprFromType(string $type, string $expr): string
|
|
{
|
|
if ($type === Type::FLOAT) {
|
|
return $this->convertFloatExpr($expr);
|
|
}
|
|
if ($type === Type::INT) {
|
|
return $this->convertIntExpr($expr);
|
|
}
|
|
if ($type === Type::BOOL) {
|
|
return $this->convertBoolExpr($expr);
|
|
}
|
|
if ($type === Type::STR) {
|
|
return $this->convertStringExpr($expr);
|
|
}
|
|
if ($type === Type::ARRAY) {
|
|
return $this->convertArrayExpr($expr);
|
|
}
|
|
if ($type === Type::OBJECT) {
|
|
return $this->convertObjectExpr($expr);
|
|
}
|
|
|
|
return $expr;
|
|
}
|
|
|
|
protected function convertVarType($var, $expr): string
|
|
{
|
|
if ($this->hasVar($var)) {
|
|
return $this->convertExprFromType($this->getVarType($var), $expr);
|
|
}
|
|
|
|
return $expr;
|
|
}
|
|
|
|
protected function convertToRef(NodeAbstract $expr): string
|
|
{
|
|
$this->checkLeftValue($expr);
|
|
$var = $this->parseIdentifier($expr);
|
|
if ($this->isVarExpr($expr) and $this->isNativeTypeVar($var)) {
|
|
$this->context->localVars[$var] = Type::VAR;
|
|
}
|
|
return $this->parseIdentifier($expr) . '.toReference()';
|
|
}
|
|
|
|
}
|
|
|