Finish listReference

This commit is contained in:
Daniil Gentili 2020-10-05 11:03:24 +02:00
parent 2cb2f73898
commit 37e0cfac27
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
2 changed files with 28 additions and 13 deletions

View File

@ -17,7 +17,6 @@ use PhpParser\Node\Expr\Cast\Bool_;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\Expr\Variable;
@ -181,13 +180,13 @@ class Context
$parent->setAttribute('currentNodeIndex', $nodeKeyIndex - 1);
return; // Done, inserted!
}
// Cannot insert, parent is not a statement
$node = &$parent->{$nodeKey};
// If we insert before a conditional branch of a conditional expression,
// make sure the conditional branch has no side effects;
// make sure the conditional branch has no side effects;
// if it does, turn the entire conditional expression into an if, and bubble it up
//
//
// Unless we want to go crazy, do not consider side effect evaluation order for stuff like function call arguments, maths and so on.
//
if ($node instanceof BooleanOr && $nodeKey === 'right' && Tools::hasSideEffects($node->right)) {

View File

@ -6,6 +6,7 @@ use Phabel\Context;
use Phabel\Plugin;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\AssignRef;
use PhpParser\Node\Expr\List_;
@ -26,13 +27,13 @@ class ListReference extends Plugin
*/
public function enterForeach(Foreach_ $node, Context $ctx): void
{
if (!($node->valueVar instanceof List_ || $node->valueVar instanceof Array_) || !$this->shouldSplit($node->valueVar)) {
if (!($node->valueVar instanceof List_ || $node->valueVar instanceof Array_) || !$this->shouldSplit($node->valueVar, true)) {
return;
}
$list = $node->valueVar;
$var = $node->valueVar = $ctx->getVariable();
$assignments = self::splitList($list, $var);
$node->stmts
$node->stmts = \array_merge($assignments, $node->stmts);
}
/**
* Parse list assignment with custom keys.
@ -46,8 +47,19 @@ class ListReference extends Plugin
if (!($node->var instanceof List_ || $node->var instanceof Array_) || !$this->shouldSplit($node->var)) {
return;
}
[$node->var, $array] = $this->splitList($node->var, $ctx);
$node->expr = self::callPoly('destructure', $array, $node->expr);
$isStmt = $ctx->parents[0]->getAttribute('currentNode') === 'stmts';
$list = $node->var;
$var = $ctx->getVariable();
$assignments = self::splitList($list, $var);
if ($isStmt) {
$last = \array_pop($assignments);
$ctx->insertBefore($node, new Assign($node->var, $node->expr), ...$assignments);
return $last;
}
// On newer versions of php, list assignment returns the original array
$ctx->insertBefore($node, new Assign($var, $node->expr), ...$assignments);
return $var;
}
/**
* Split referenced list into multiple assignments.
@ -66,9 +78,7 @@ class ListReference extends Plugin
continue;
}
$curKey = $item->key ?? $key++;
if ($item->value instanceof List_ || $item->value instanceof Array_) {
// Do nothing, will re-split later if needed
} else if ($item->byRef) {
if ($item->byRef) {
$assignments []= new AssignRef($item->value, new ArrayDimFetch($var, $curKey));
} else {
$assignments []= new Assign($item->value, new ArrayDimFetch($var, $curKey));
@ -79,15 +89,21 @@ class ListReference extends Plugin
/**
* Whether this is a referenced list.
*
* @param List_|Array_ $list List
* @param List_|Array_ $list List
* @param bool $recurse Whether to recurse while checking
*
* @return boolean
*/
private function shouldSplit($list): bool
private function shouldSplit($list, bool $recurse = false): bool
{
/** @var ArrayItem $item */
foreach ($list->items ?? [] as $item) {
if ($item->byRef) {
return true;
} elseif ($recurse && ($item->value instanceof List_ || $item->value instanceof Array_)) {
if ($this->shouldSplit($item->value, $recurse)) {
return true;
}
}
}
return false;