Finish listReference
This commit is contained in:
parent
2cb2f73898
commit
37e0cfac27
|
@ -17,7 +17,6 @@ use PhpParser\Node\Expr\Cast\Bool_;
|
||||||
use PhpParser\Node\Expr\Closure;
|
use PhpParser\Node\Expr\Closure;
|
||||||
use PhpParser\Node\Expr\FuncCall;
|
use PhpParser\Node\Expr\FuncCall;
|
||||||
use PhpParser\Node\Expr\MethodCall;
|
use PhpParser\Node\Expr\MethodCall;
|
||||||
use PhpParser\Node\Expr\New_;
|
|
||||||
use PhpParser\Node\Expr\StaticCall;
|
use PhpParser\Node\Expr\StaticCall;
|
||||||
use PhpParser\Node\Expr\Ternary;
|
use PhpParser\Node\Expr\Ternary;
|
||||||
use PhpParser\Node\Expr\Variable;
|
use PhpParser\Node\Expr\Variable;
|
||||||
|
@ -181,13 +180,13 @@ class Context
|
||||||
$parent->setAttribute('currentNodeIndex', $nodeKeyIndex - 1);
|
$parent->setAttribute('currentNodeIndex', $nodeKeyIndex - 1);
|
||||||
return; // Done, inserted!
|
return; // Done, inserted!
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cannot insert, parent is not a statement
|
// Cannot insert, parent is not a statement
|
||||||
$node = &$parent->{$nodeKey};
|
$node = &$parent->{$nodeKey};
|
||||||
// If we insert before a conditional branch of a conditional expression,
|
// 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
|
// 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.
|
// 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)) {
|
if ($node instanceof BooleanOr && $nodeKey === 'right' && Tools::hasSideEffects($node->right)) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ use Phabel\Context;
|
||||||
use Phabel\Plugin;
|
use Phabel\Plugin;
|
||||||
use PhpParser\Node\Expr\Array_;
|
use PhpParser\Node\Expr\Array_;
|
||||||
use PhpParser\Node\Expr\ArrayDimFetch;
|
use PhpParser\Node\Expr\ArrayDimFetch;
|
||||||
|
use PhpParser\Node\Expr\ArrayItem;
|
||||||
use PhpParser\Node\Expr\Assign;
|
use PhpParser\Node\Expr\Assign;
|
||||||
use PhpParser\Node\Expr\AssignRef;
|
use PhpParser\Node\Expr\AssignRef;
|
||||||
use PhpParser\Node\Expr\List_;
|
use PhpParser\Node\Expr\List_;
|
||||||
|
@ -26,13 +27,13 @@ class ListReference extends Plugin
|
||||||
*/
|
*/
|
||||||
public function enterForeach(Foreach_ $node, Context $ctx): void
|
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;
|
return;
|
||||||
}
|
}
|
||||||
$list = $node->valueVar;
|
$list = $node->valueVar;
|
||||||
$var = $node->valueVar = $ctx->getVariable();
|
$var = $node->valueVar = $ctx->getVariable();
|
||||||
$assignments = self::splitList($list, $var);
|
$assignments = self::splitList($list, $var);
|
||||||
$node->stmts
|
$node->stmts = \array_merge($assignments, $node->stmts);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Parse list assignment with custom keys.
|
* 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)) {
|
if (!($node->var instanceof List_ || $node->var instanceof Array_) || !$this->shouldSplit($node->var)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[$node->var, $array] = $this->splitList($node->var, $ctx);
|
$isStmt = $ctx->parents[0]->getAttribute('currentNode') === 'stmts';
|
||||||
$node->expr = self::callPoly('destructure', $array, $node->expr);
|
$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.
|
* Split referenced list into multiple assignments.
|
||||||
|
@ -66,9 +78,7 @@ class ListReference extends Plugin
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$curKey = $item->key ?? $key++;
|
$curKey = $item->key ?? $key++;
|
||||||
if ($item->value instanceof List_ || $item->value instanceof Array_) {
|
if ($item->byRef) {
|
||||||
// Do nothing, will re-split later if needed
|
|
||||||
} else if ($item->byRef) {
|
|
||||||
$assignments []= new AssignRef($item->value, new ArrayDimFetch($var, $curKey));
|
$assignments []= new AssignRef($item->value, new ArrayDimFetch($var, $curKey));
|
||||||
} else {
|
} else {
|
||||||
$assignments []= new Assign($item->value, new ArrayDimFetch($var, $curKey));
|
$assignments []= new Assign($item->value, new ArrayDimFetch($var, $curKey));
|
||||||
|
@ -79,15 +89,21 @@ class ListReference extends Plugin
|
||||||
/**
|
/**
|
||||||
* Whether this is a referenced list.
|
* 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
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
private function shouldSplit($list): bool
|
private function shouldSplit($list, bool $recurse = false): bool
|
||||||
{
|
{
|
||||||
|
/** @var ArrayItem $item */
|
||||||
foreach ($list->items ?? [] as $item) {
|
foreach ($list->items ?? [] as $item) {
|
||||||
if ($item->byRef) {
|
if ($item->byRef) {
|
||||||
return true;
|
return true;
|
||||||
|
} elseif ($recurse && ($item->value instanceof List_ || $item->value instanceof Array_)) {
|
||||||
|
if ($this->shouldSplit($item->value, $recurse)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in New Issue