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