diff --git a/phpunit/code/bigint-post-inc.php b/phpunit/code/bigint-post-inc.php new file mode 100644 index 00000000..708ccfbf --- /dev/null +++ b/phpunit/code/bigint-post-inc.php @@ -0,0 +1,8 @@ +exec('Cannot concat string to array', 'assign-op-concat-array.php'); } + + public function testBigIntPreInc() + { + $this->exec('Cannot use ++ on php::BigInt', 'bigint-pre-inc.php'); + } + + public function testBigIntPostInc() + { + $this->exec('Cannot use ++ on php::BigInt', 'bigint-post-inc.php'); + } + + public function testDecimalPreDec() + { + $this->exec('Cannot use -- on php::Decimal', 'decimal-pre-dec.php'); + } } diff --git a/src/Php/CompilerBase.php b/src/Php/CompilerBase.php index ed41ac20..59bc8342 100644 --- a/src/Php/CompilerBase.php +++ b/src/Php/CompilerBase.php @@ -3018,6 +3018,10 @@ class CompilerBase extends \PhpAot\Core\Translator protected function parsePreInc(Expr\PreInc $expr): string { + $type = $this->detectVarType($expr->var); + if ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) { + $this->fatalError($expr, 'Cannot use ++ on ' . $type . '. Use += 1 instead (Big* types are immutable).'); + } return '++' . $this->parseIdentifier($expr->var); } @@ -3721,6 +3725,11 @@ class CompilerBase extends \PhpAot\Core\Translator if ($this->isVarExpr($expr->var) and !$this->hasVar($var)) { $this->errorUndefinedVariable($expr->var); } + $type = $this->detectVarType($expr->var); + if ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) { + $opName = $op === '+' ? '++' : '--'; + $this->fatalError($expr, "Cannot use {$opName} on {$type}. Use " . ($op === '+' ? '+= 1' : '-= 1') . ' instead (Big* types are immutable).'); + } return $var . str_repeat($op, 2); } if ($this->isStaticPropertyFetch($expr->var)) { @@ -3828,6 +3837,10 @@ class CompilerBase extends \PhpAot\Core\Translator protected function parsePreDec(Expr\PreDec $expr): string { + $type = $this->detectVarType($expr->var); + if ($type === self::TYPE_BIGINT || $type === self::TYPE_DECIMAL || $type === self::TYPE_BIGFLOAT) { + $this->fatalError($expr, 'Cannot use -- on ' . $type . '. Use -= 1 instead (Big* types are immutable).'); + } return '--' . $this->parseIdentifier($expr->var); } diff --git a/tests/aot/bigint/assign_op.phpt b/tests/aot/bigint/assign_op.phpt new file mode 100644 index 00000000..1212d2b5 --- /dev/null +++ b/tests/aot/bigint/assign_op.phpt @@ -0,0 +1,46 @@ +--TEST-- +BigInt compound assignment operators (+=, -=, *=, /=, %=) +--FILE-- +toString(); echo "\n"; + + // BigInt += with BigInt + $b = std::bigInt("99999999999999999999"); + $b += std::bigInt(1); + echo $b->toString(); echo "\n"; + + // BigInt -= + $c = std::bigInt(1000); + $c -= 300; + echo $c->toString(); echo "\n"; + + // BigInt *= + $d = std::bigInt(100); + $d *= 5; + echo $d->toString(); echo "\n"; + + // BigInt /= + $e = std::bigInt(100); + $e /= 3; + echo $e->toString(); echo "\n"; + + // BigInt %= + $f = std::bigInt(100); + $f %= 7; + echo $f->toString(); echo "\n"; +} +?> +--EXPECT-- +150 +100000000000000000000 +700 +500 +33 +2 diff --git a/tests/aot/bigint/operator.phpt b/tests/aot/bigint/operator.phpt new file mode 100644 index 00000000..5645657c --- /dev/null +++ b/tests/aot/bigint/operator.phpt @@ -0,0 +1,49 @@ +--TEST-- +BigInt binary operators (+, -, *, /, %) and unary minus +--FILE-- +toString(); echo "\n"; + // Int + BigInt + $c = 200 + $a; + echo $c->toString(); echo "\n"; + // BigInt - Int + $d = $a - 30; + echo $d->toString(); echo "\n"; + // BigInt * Int + $e = $a * 5; + echo $e->toString(); echo "\n"; + // BigInt / Int + $f = $a / 3; + echo $f->toString(); echo "\n"; + // BigInt % Int + $g = $a % 7; + echo $g->toString(); echo "\n"; + + // BigInt ** Int + $h = std::bigInt(2) ** 10; + echo $h->toString(); echo "\n"; + + // Unary minus + $i = -$a; + echo $i->toString(); echo "\n"; + echo (-$i)->toString(); echo "\n"; +} +?> +--EXPECT-- +150 +300 +70 +500 +33 +2 +1024 +-100 +100 diff --git a/tests/aot/decimal/arithmetic.phpt b/tests/aot/decimal/arithmetic.phpt new file mode 100644 index 00000000..284993c5 --- /dev/null +++ b/tests/aot/decimal/arithmetic.phpt @@ -0,0 +1,36 @@ +--TEST-- +Decimal arithmetic operations +--FILE-- +add($b)->toString(); echo "\n"; + // Decimal - Decimal + echo $a->sub($b)->toString(); echo "\n"; + // Decimal * Decimal + echo $a->mul($b)->toString(); echo "\n"; + // Decimal / Decimal + echo $a->div($b)->toString(); echo "\n"; + // Decimal mod + $c = std::decimal("17.5"); + echo $c->mod(std::decimal("5.0"))->toString(); echo "\n"; + // Decimal neg + echo $a->neg()->toString(); echo "\n"; + // Decimal abs + echo $a->neg()->abs()->toString(); echo "\n"; +} +?> +--EXPECT-- +150.75 +50.25 +5050.1250 +2 +2.5 +-100.50 +100.50 diff --git a/tests/aot/decimal/assign_op.phpt b/tests/aot/decimal/assign_op.phpt new file mode 100644 index 00000000..2a446097 --- /dev/null +++ b/tests/aot/decimal/assign_op.phpt @@ -0,0 +1,45 @@ +--TEST-- +Decimal compound assignment operators (+=, -=, *=, /=, %=) +--FILE-- +toString(); echo "\n"; + + // Decimal += with int + $a += 100; + echo $a->toString(); echo "\n"; + + // Decimal -= + $b = std::decimal("500.00"); + $b -= 123.45; + echo $b->toString(); echo "\n"; + + // Decimal *= + $c = std::decimal("50.5"); + $c *= 2; + echo $c->toString(); echo "\n"; + + // Decimal /= + $d = std::decimal("100.00"); + $d /= 4; + echo $d->toString(); echo "\n"; + + // Decimal %= + $e = std::decimal("17.5"); + $e %= 5.0; + echo $e->toString(); echo "\n"; +} +?> +--EXPECT-- +125.75 +225.75 +376.55 +101.0 +25.00 +2.5 diff --git a/tests/aot/decimal/compare.phpt b/tests/aot/decimal/compare.phpt new file mode 100644 index 00000000..1b348c20 --- /dev/null +++ b/tests/aot/decimal/compare.phpt @@ -0,0 +1,26 @@ +--TEST-- +Decimal comparison and conversions +--FILE-- +cmp($b); echo "\n"; + echo "cmp(b,a)="; echo $b->cmp($a); echo "\n"; + echo "cmp(a,a)="; echo $a->cmp($a); echo "\n"; + + // conversion + echo $a->toInt(); echo "\n"; + echo $a->toString(); echo "\n"; +} +?> +--EXPECT-- +cmp(a,b)=-1 +cmp(b,a)=1 +cmp(a,a)=0 +123 +123.456 diff --git a/tests/aot/decimal/operator.phpt b/tests/aot/decimal/operator.phpt new file mode 100644 index 00000000..407d5359 --- /dev/null +++ b/tests/aot/decimal/operator.phpt @@ -0,0 +1,51 @@ +--TEST-- +Decimal operator overloading (+, -, *, /, %) and comparisons +--FILE-- +toString(); echo "\n"; + // Int + Decimal + $b = 200 + $dec; + echo $b->toString(); echo "\n"; + // Decimal - Float + $c = $dec - 0.25; + echo $c->toString(); echo "\n"; + // Decimal * Int + $d = $dec * 4; + echo $d->toString(); echo "\n"; + // Decimal / Int + $e = $dec / 5; + echo $e->toString(); echo "\n"; + // Decimal % Int + $f = $dec % 7; + echo $f->toString(); echo "\n"; + + // Comparisons + echo (int)($dec > 50); echo "\n"; + echo (int)($dec < 200); echo "\n"; + echo (int)($dec == 100.25); echo "\n"; + echo (int)($dec != 100); echo "\n"; + echo (int)($dec <= 100.25); echo "\n"; + echo (int)($dec >= 100); echo "\n"; +} +?> +--EXPECT-- +150.25 +300.25 +100.00 +401.00 +20.05 +2.25 +1 +1 +1 +1 +1 +1 diff --git a/tests/aot/decimal/unary_minus.phpt b/tests/aot/decimal/unary_minus.phpt new file mode 100644 index 00000000..903b5fb3 --- /dev/null +++ b/tests/aot/decimal/unary_minus.phpt @@ -0,0 +1,21 @@ +--TEST-- +Decimal unary minus operator +--FILE-- +toString(); echo "\n"; + // Double minus + $c = -$b; + echo $c->toString(); echo "\n"; +} +?> +--EXPECT-- +-123.456 +123.456