From 739152ba1463ac4c6f43ed498f55b401ab8a6025 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Tue, 6 Jan 2026 18:16:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=AF=AD=E6=B3=95=20**=3D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/str_offset_set.php | 7 +++++ src/Php/Translator.php | 25 ++++++++++++++++++ tests/aot/pow-assign-op.phpt | 10 +++++++ .../ast/ast_serialize_backtick_literal.phpt | 16 ++++++++++++ tests/zend/ast/ast_serialize_floats.phpt | 26 +++++++++++++++++++ tests/zend/ast/zend-pow-assign.phpt | 16 ++++++++++++ 6 files changed, 100 insertions(+) create mode 100644 examples/str_offset_set.php create mode 100644 tests/aot/pow-assign-op.phpt create mode 100644 tests/zend/ast/ast_serialize_backtick_literal.phpt create mode 100644 tests/zend/ast/ast_serialize_floats.phpt create mode 100644 tests/zend/ast/zend-pow-assign.phpt diff --git a/examples/str_offset_set.php b/examples/str_offset_set.php new file mode 100644 index 00000000..9deecb37 --- /dev/null +++ b/examples/str_offset_set.php @@ -0,0 +1,7 @@ +parseAssignOpShiftRight($expr); case 'Expr_AssignOp_BitwiseAnd': return $this->parseAssignOpBitwiseAnd($expr); + case 'Expr_AssignOp_Pow': + return $this->parseAssignOpPow($expr); case 'Expr_BinaryOp_Mul': return $this->parseBinaryOpMul($expr); case 'Expr_BinaryOp_Concat': @@ -676,6 +678,8 @@ class Translator extends \PhpAot\Core\Translator return $this->parseClone($expr); case 'Expr_Throw': return $this->parseThrow($expr); + case 'Expr_ShellExec': + return $this->parseShellExec($expr); case 'Name_FullyQualified': return $expr->name; case 'Scalar_Int': @@ -801,6 +805,11 @@ class Translator extends \PhpAot\Core\Translator return $op === '.='; } + private function isAssignOpPow(string $op): bool + { + return $op === '**='; + } + /** * 尽可能转为数字,优先级 浮点 > 整数 > 字符串 */ @@ -1181,10 +1190,16 @@ class Translator extends \PhpAot\Core\Translator $expr = $this->parseIdentifier($node->expr); $leftExprType = $node->var->getType(); if ($leftExprType === self::EXPR_VARIABLE) { + if (!$this->hasVar($var)) { + $this->fatalError($node->var, 'Cannot assign to undefined variable'); + } $type = $this->detectVarType($node->var); $rightExprStr = $this->convertExprType($expr, $type, $this->detectExprType($node->expr)); if ($this->isAssignOpConcat($op)) { return $var . '.append(' . $rightExprStr . ')'; + } elseif ($this->isAssignOpPow($op)) { + $powExpr = 'php::call(php::pow, {' . $var . ', ' . $rightExprStr . '})'; + return $var . ' = ' . $this->convertVarType($var, $powExpr); } else { return $var . ' ' . $op . ' ' . $rightExprStr; } @@ -1255,6 +1270,11 @@ class Translator extends \PhpAot\Core\Translator return $this->parseAssignOp($expr, '&='); } + private function parseAssignOpPow(mixed $expr): string + { + return $this->parseAssignOp($expr, '**='); + } + private function fatalError(Node $node, string $msg): void { $this->climate->red("Fatal error: $msg in {$this->file}:" . $node->getStartLine()); @@ -2314,4 +2334,9 @@ class Translator extends \PhpAot\Core\Translator return $code; } + + private function parseShellExec(mixed $expr): string + { + return 'php::call("shell_exec", {' . $this->parseInterpolatedString($expr) . '})'; + } } diff --git a/tests/aot/pow-assign-op.phpt b/tests/aot/pow-assign-op.phpt new file mode 100644 index 00000000..ce6a0b13 --- /dev/null +++ b/tests/aot/pow-assign-op.phpt @@ -0,0 +1,10 @@ +--TEST-- +strlen +--FILE-- + +--EXPECT-- +int(1024) diff --git a/tests/zend/ast/ast_serialize_backtick_literal.phpt b/tests/zend/ast/ast_serialize_backtick_literal.phpt new file mode 100644 index 00000000..b2583a0a --- /dev/null +++ b/tests/zend/ast/ast_serialize_backtick_literal.phpt @@ -0,0 +1,16 @@ +--TEST-- +Serialization of backtick literal is incorrect +--INI-- +zend.assertions=1 +--FILE-- +getMessage(), ' failed', PHP_EOL; +} + +?> +--EXPECT-- +assert(): failed diff --git a/tests/zend/ast/ast_serialize_floats.phpt b/tests/zend/ast/ast_serialize_floats.phpt new file mode 100644 index 00000000..d27e8a7c --- /dev/null +++ b/tests/zend/ast/ast_serialize_floats.phpt @@ -0,0 +1,26 @@ +--TEST-- +Serialization of floats are correct +--INI-- +--FILE-- +getMessage(), ' failed', PHP_EOL; +} +try { + assert(!is_float(1.1)); +} catch (AssertionError $e) { + echo 'assert(): ', $e->getMessage(), ' failed', PHP_EOL; +} +try { + assert(!is_float(1234.5678)); +} catch (AssertionError $e) { + echo 'assert(): ', $e->getMessage(), ' failed', PHP_EOL; +} +?> +--EXPECT-- +assert(): failed +assert(): failed +assert(): failed \ No newline at end of file diff --git a/tests/zend/ast/zend-pow-assign.phpt b/tests/zend/ast/zend-pow-assign.phpt new file mode 100644 index 00000000..09196158 --- /dev/null +++ b/tests/zend/ast/zend-pow-assign.phpt @@ -0,0 +1,16 @@ +--TEST-- +ZEND_POW_ASSIGN +--INI-- +zend.assertions=1 +--FILE-- +getMessage(), ' failed', PHP_EOL; +} +?> +--EXPECT-- +assert(): failed