compiler icon indicating copy to clipboard operation
compiler copied to clipboard

Logical Operators and Assignment Expressions:

Open thekid opened this issue 3 years ago • 1 comments

Add ||= and &&= operators accompanying the ??= operator:

$a ||= $b; // equivalent of $a || ($a= $b);
$a &&= $b; // equivalent of $a && ($a= $b);
$a ??= $b; // equivalent of $a ?? ($a= $b); - EXISTS in PHP!

https://github.com/tc39/proposal-logical-assignment https://github.com/dotnet/csharplang/issues/1718

thekid avatar Jan 29 '22 13:01 thekid

Implementation:

diff --git a/src/main/php/lang/ast/emit/PHP.class.php b/src/main/php/lang/ast/emit/PHP.class.php
index ac3d93a..79cf654 100755
--- a/src/main/php/lang/ast/emit/PHP.class.php
+++ b/src/main/php/lang/ast/emit/PHP.class.php
@@ -789,7 +789,15 @@ abstract class PHP extends Emitter {
 
   protected function emitAssignment($result, $assignment) {
     $this->emitAssign($result, $assignment->variable);
-    $result->out->write($assignment->operator);
+
+    if ('||=' === $assignment->operator || '&&=' === $assignment->operator) {
+      $result->out->write(substr($assignment->operator, 0, 2));
+      $this->emitOne($result, $assignment->variable);
+      $result->out->write('=');
+    } else {
+      $result->out->write($assignment->operator);
+    }
+
     $this->emitOne($result, $assignment->expression);
   }
 
diff --git a/src/test/php/lang/ast/unittest/emit/OperatorTest.class.php b/src/test/php/lang/ast/unittest/emit/OperatorTest.class.php
index 0e1833b..7c87653 100755
--- a/src/test/php/lang/ast/unittest/emit/OperatorTest.class.php
+++ b/src/test/php/lang/ast/unittest/emit/OperatorTest.class.php
@@ -65,4 +65,28 @@ class OperatorTest extends EmittingTest {
 
     Assert::equals($expected, $r[0]);
   }
+
+  #[Test, Values([[false, true], [true, true]])]
+  public function logical_or_assignment($value, $expected) {
+    $r= $this->run('class %T {
+      public function run($arg) {
+        $arg||= true;
+        return $arg;
+      }
+    }', $value);
+
+    Assert::equals($expected, $r);
+  }
+
+  #[Test, Values([[true, false], [false, false]])]
+  public function logical_and_assignment($value, $expected) {
+    $r= $this->run('class %T {
+      public function run($arg) {
+        $arg&&= false;
+        return $arg;
+      }
+    }', $value);
+
+    Assert::equals($expected, $r);
+  }
 }
\ No newline at end of file

thekid avatar Mar 24 '24 20:03 thekid