diff --git a/src/Php/Translator.php b/src/Php/Translator.php index f75f4581..455df110 100644 --- a/src/Php/Translator.php +++ b/src/Php/Translator.php @@ -48,7 +48,9 @@ class Translator extends \PhpAot\Core\Translator private array $internalFunctions = []; - private int $optimizeLevel = 5; + private int $optimizeLevel = 0; + private int $floatPrecision = 17; + private bool $debugInfo = true; private bool $verbose = false; private string $file; private string $dir; @@ -406,6 +408,8 @@ class Translator extends \PhpAot\Core\Translator return $this->parseAssignOpConcat($expr); case 'Expr_AssignOp_ShiftRight': return $this->parseAssignOpShiftRight($expr); + case 'Expr_AssignOp_BitwiseAnd': + return $this->parseAssignOpBitwiseAnd($expr); case 'Expr_BinaryOp_Mul': return $this->parseBinaryOpMul($expr); case 'Expr_BinaryOp_Concat': @@ -480,6 +484,8 @@ class Translator extends \PhpAot\Core\Translator return $this->parseUnaryPlus($expr); case 'InterpolatedStringPart': return $this->parseInterpolatedStringPart($expr); + case 'Expr_Cast_Array': + return $this->parseCastArray($expr); case 'Expr_Exit': return $this->parseExit($expr); default: @@ -597,11 +603,11 @@ class Translator extends \PhpAot\Core\Translator if ($leftType === self::TYPE_FLOAT) { $rightExpr = $this->convertExprType($rightExpr, self::TYPE_FLOAT, $rightType); } elseif ($rightType === self::TYPE_FLOAT) { - $leftExpr = $this->convertExprType($leftExpr, self::TYPE_FLOAT, $leftType); + $leftExpr = $this->convertExprType($leftExpr, $leftType, self::TYPE_FLOAT); } elseif ($leftType === self::TYPE_INT) { $rightExpr = $this->convertExprType($rightExpr, self::TYPE_INT, $rightType); } elseif ($rightType === self::TYPE_INT) { - $leftExpr = $this->convertExprType($leftExpr, self::TYPE_INT, $leftType); + $leftExpr = $this->convertExprType($leftExpr, $leftType, self::TYPE_INT); } return $leftExpr . ' ' . $op . ' ' . $rightExpr; @@ -667,14 +673,28 @@ class Translator extends \PhpAot\Core\Translator case 'Expr_Cast_Float': case 'Scalar_Float': return self::TYPE_FLOAT; + case 'Expr_Cast_Bool': case 'Scalar_Bool': return self::TYPE_BOOL; case 'Expr_Array': return 'php::Array'; case 'Expr_BinaryOp_Plus': case 'Expr_BinaryOp_Minus': + case 'Expr_BinaryOp_Mul': + case 'Expr_BinaryOp_Div': + case 'Expr_BinaryOp_Mod': + case 'Expr_BinaryOp_Pow': + case 'Expr_BinaryOp_ShiftLeft': + case 'Expr_BinaryOp_ShiftRight': + case 'Expr_BinaryOp_BitwiseAnd': + case 'Expr_BinaryOp_BitwiseOr': + case 'Expr_BinaryOp_BitwiseXor': + case 'Expr_BinaryOp_BooleanAnd': $leftType = $this->detectExprType($expr->left); $rightType = $this->detectExprType($expr->right); + if ($leftType === self::TYPE_FLOAT || $rightType === self::TYPE_FLOAT) { + return self::TYPE_FLOAT; + } if ($leftType === self::TYPE_INT || $rightType === self::TYPE_INT) { return self::TYPE_INT; } @@ -713,43 +733,42 @@ class Translator extends \PhpAot\Core\Translator return self::TYPE_ARRAY .'{}'; } - // 检查一下数组的赋值方式,是否为索引数组或关联数组,若是混杂模式,需要改为多行插入 - $assocArray = (bool)$items[0]->key; - $mixed = false; + $assocArray = false; foreach ($items as $item) { if ($item->key) { - if (!$assocArray) { - $mixed = true; - break; - } - } else { - if ($assocArray) { - $mixed = true; - break; - } + $assocArray = true; + break; } } - if ($mixed) { - abort($node); - } else { - $list = []; - $this->indentLevel++; - foreach ($items as $item) { - if ($item->key) { - $list[] = $this->getIndent() . '{ ' . $this->parseIdentifier($item->key) . ', ' . - self::TYPE_VAR . '(' . $this->parseIdentifier($item->value) . ') }'; - } else { - $value = $this->parseIdentifier($item->value); - $list[] = $this->getIndent() . self::TYPE_VAR . '(' . $value . ')'; - } + $list = []; + $this->indentLevel++; + foreach ($items as $item) { + /** + * 数组赋值语句 + * $array = [1, 2, $x = 3]; + */ + if ($item->value->getType() === 'Expr_Assign') { + $left = $item->value->var; + $this->beforeStmtLines[] = $this->getIndent() . $this->parseExpr($item->value) . ';'; + $value = $this->parseIdentifier($left); + } else { + $value = $this->parseIdentifier($item->value); + } + if ($assocArray) { + // TODO 混杂模式数组赋值 + $key = $item->key ? $this->parseIdentifier($item->key) : 'php::null'; + $list[] = $this->getIndent() . '{ ' . $key . ', ' . + self::TYPE_VAR . '(' . $value . ') }'; + } else { + $list[] = $this->getIndent() . self::TYPE_VAR . '(' . $value . ')'; } - $this->indentLevel--; - return self::TYPE_ARRAY . '{' . PHP_EOL . - implode(', ' . PHP_EOL, $list) . PHP_EOL . - $this->getIndent() . - '}'; } + $this->indentLevel--; + return self::TYPE_ARRAY . '{' . PHP_EOL . + implode(', ' . PHP_EOL, $list) . PHP_EOL . + $this->getIndent() . + '}'; } private function parseType($type) @@ -812,7 +831,11 @@ class Translator extends \PhpAot\Core\Translator public function compileFile($file): void { - $cmd = 'g++ -c ' . $file . ' -o ' . $file . '.o ' . $this->parseIncludes() . ' -O' . $this->optimizeLevel; + $cmd = 'g++ -c ' . $file . ' -o ' . $file . '.o ' . $this->parseIncludes(); + $cmd .= ' -O' . $this->optimizeLevel; + if ($this->debugInfo) { + $cmd .= ' -g'; + } echo $cmd . PHP_EOL; shell_exec($cmd); } @@ -1128,6 +1151,16 @@ class Translator extends \PhpAot\Core\Translator return 'php::to_float(' . $expr . ')'; } + private function convertStringExpr(string $expr): string + { + return 'php::to_string(' . $expr . ')'; + } + + private function convertArrayExpr(string $expr): string + { + return 'php::to_array(' . $expr . ')'; + } + private function convertBoolExpr(string $expr): string { return 'php::to_bool(' . $expr . ')'; @@ -1343,13 +1376,13 @@ class Translator extends \PhpAot\Core\Translator private function convertExprType(string $expr, $leftType, $rightType): string { - if ($leftType === self::TYPE_FLOAT && $rightType !== self::TYPE_FLOAT) { + if ($leftType === self::TYPE_FLOAT or $rightType === self::TYPE_FLOAT) { return $this->convertFloatExpr($expr); } - if ($leftType === self::TYPE_INT && $rightType !== self::TYPE_INT) { + if ($leftType === self::TYPE_INT or $rightType === self::TYPE_INT) { return $this->convertIntExpr($expr); } - if ($leftType === self::TYPE_BOOL && $rightType !== self::TYPE_BOOL) { + if ($leftType === self::TYPE_BOOL or $rightType === self::TYPE_BOOL) { return $this->convertBoolExpr($expr); } return $expr; @@ -1569,6 +1602,7 @@ class Translator extends \PhpAot\Core\Translator private function parseScalarFloat(Node $expr): string { $value = $expr->value; + if (is_nan($value)) { return self::VALUE_NAN; } elseif (is_infinite($value)) { @@ -1576,7 +1610,7 @@ class Translator extends \PhpAot\Core\Translator } else if (floor($value) == $value && abs($value) < 1e15) { return number_format($value, 1, '.', ''); } else { - return $value; + return sprintf('%.' . $this->floatPrecision . 'g', $value); } } @@ -1591,4 +1625,15 @@ class Translator extends \PhpAot\Core\Translator } } } + + private function parseAssignOpBitwiseAnd(mixed $node): string + { + $var = $this->parseIdentifier($node->var); + return $var . ' &= ' . $this->parseIdentifier($node->expr); + } + + private function parseCastArray(mixed $expr): string + { + return $this->convertArrayExpr($this->parseIdentifier($expr->expr)); + } } diff --git a/tests/zend/add_005.phpt b/tests/zend/add_005.phpt new file mode 100644 index 00000000..1cb3774c --- /dev/null +++ b/tests/zend/add_005.phpt @@ -0,0 +1,20 @@ +--TEST-- +adding integers to doubles +--FILE-- + +--EXPECT-- +float(2834756759.123123) +float(2834756759.123123) +Done diff --git a/tests/zend/and_001.phpt b/tests/zend/and_001.phpt new file mode 100644 index 00000000..c49af66a --- /dev/null +++ b/tests/zend/and_001.phpt @@ -0,0 +1,39 @@ +--TEST-- +bitwise AND and strings +--FILE-- + +--EXPECT-- +string(3) "020" +string(4) "pead" +string(4) "pead" +string(4) "pead" +string(4) "pead" +Done diff --git a/tests/zend/array_hash_zero.phpt b/tests/zend/array_hash_zero.phpt new file mode 100644 index 00000000..0939d5bf --- /dev/null +++ b/tests/zend/array_hash_zero.phpt @@ -0,0 +1,20 @@ +--TEST-- +Accept hashes being equal to zero +--FILE-- + 32, + "\xf7\x17\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x6b\x03\x6a\x13\x63\x17\x6b\x1d\x67" => 64, +]; + +foreach ($hashes as $hash => $bits) { + var_dump($hashes[$hash], $bits); +} + +?> +--EXPECT-- +int(32) +int(32) +int(64) +int(64) diff --git a/tests/zend/div_001.phpt b/tests/zend/div_001.phpt new file mode 100644 index 00000000..11cf8975 --- /dev/null +++ b/tests/zend/div_001.phpt @@ -0,0 +1,32 @@ +--TEST-- +dividing doubles +--INI-- +precision=14 +--FILE-- + +--EXPECT-- +float(394758.39454545453) +float(394758.39454545453) +float(394758.39454545453) +Done diff --git a/tests/zend/double_array_cast.phpt b/tests/zend/double_array_cast.phpt new file mode 100644 index 00000000..aaee8cd9 --- /dev/null +++ b/tests/zend/double_array_cast.phpt @@ -0,0 +1,18 @@ +--TEST-- +Double array cast +--FILE-- + +--EXPECT-- +array(3) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) +}