Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions lib/Block.php
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ private static function findVariableInParentFrames(Operand $op, Frame $frame): ?
public function getFrame(Context $context, ?Frame $frame = null): Frame {
// Todo: build scope
$scope = [];
$cfgMerge = count($this->parents) > 1;
$scopeSize = $this->scope->count();
foreach ($this->scope as $op) {
$pos = $this->scope[$op];
Expand All @@ -296,7 +297,9 @@ public function getFrame(Context $context, ?Frame $frame = null): Frame {
continue;
}
$found = false;
$parent = $frame->block->findSlot($op, $frame);
$parent = $cfgMerge
? $this->findSlot($op, $frame)
: $frame->block->findSlot($op, $frame);
if (!is_null($parent)) {
$scope[$pos] = $parent;
$found = true;
Expand Down Expand Up @@ -327,6 +330,13 @@ public function getFrame(Context $context, ?Frame $frame = null): Frame {
$scope[$pos] = $inherited;
continue;
}
if ($cfgMerge) {
$fromJump = $this->findSlot($op, $frame);
if (null !== $fromJump) {
$scope[$pos] = $fromJump;
continue;
}
}
}
if (
$this->inheritUndefinedLocals
Expand All @@ -340,7 +350,13 @@ public function getFrame(Context $context, ?Frame $frame = null): Frame {
}
}

$return = new Frame(null, $this, $frame, ...$scope);
// CFG merge blocks (?:, if/else join) can use sparse slot indices; variadic spread reindexes (#137).
if ($cfgMerge) {
$return = new Frame(null, $this, $frame);
$return->scope = $scope;
} else {
$return = new Frame(null, $this, $frame, ...$scope);
}
$return->scriptPath = $this->scriptPath();
if (!is_null($frame) && !is_null($frame->returnVar)) {
$return->returnVar = $frame->returnVar;
Expand Down
13 changes: 4 additions & 9 deletions test/compliance/cases/language/pre_post_dec.phpt
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
--TEST--
Pre/post decrement on loop counter (VM)
language pre/post decrement (issue #137)
--FILE--
<?php
for ($i = 0; $i < 3; $i++) {
echo $i;
}
echo "\n";
$n = 2;
echo --$n, $n;
$i = 2;
echo --$i, $i, $i--;
echo "\n";
--EXPECT--
012
11
110
6 changes: 1 addition & 5 deletions test/compliance/cases/language/pre_post_inc.phpt
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
--TEST--
Pre/post increment (++/--) expression values (VM)
language pre/post increment (issue #137)
--FILE--
<?php
$i = 0;
echo ++$i, $i, $i++;
echo "\n";
$j = 5;
echo $j--, $j;
echo "\n";
--EXPECT--
112
54
31 changes: 31 additions & 0 deletions test/unit/FrameScopeSlotTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace PHPCompiler;

use PHPUnit\Framework\TestCase;

/**
* VM Frame scope must preserve compile-time slot indices (?: merge blocks, #137).
*/
final class FrameScopeSlotTest extends TestCase
{
public function testTernaryEchoesChosenBranch(): void
{
$repoRoot = dirname(__DIR__, 2);
$vm = realpath($repoRoot.'/bin/vm.php');
if (false === $vm) {
$this->markTestSkipped('bin/vm.php missing');
}
$cmd = array_merge([PHP_BINARY, $vm, '-r', 'echo true ? "yes" : "no";']);
$pipes = [];
$proc = proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes, $repoRoot);
$this->assertIsResource($proc);
$stdout = stream_get_contents($pipes[1]);
fclose($pipes[1]);
fclose($pipes[2]);
$this->assertSame(0, proc_close($proc));
$this->assertSame('yes', $stdout);
}
}
Loading