Start implementing list references

This commit is contained in:
Daniil Gentili 2020-10-04 19:58:02 +02:00
parent 1265dd87ff
commit 2cb2f73898
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7
5 changed files with 127 additions and 3 deletions

View File

@ -12,7 +12,7 @@ use Phabel\Target\Php70\IssetExpressionFixer;
use Phabel\Target\Php70\NestedExpressionFixer;
use Phabel\Target\Php70\NullCoalesceReplacer;
use Phabel\Target\Php70\ReservedNameReplacer;
use Phabel\Target\Php70\ScalarTypeHintsRemover;
use Phabel\Target\Php70\ScalarTypeHints;
use Phabel\Target\Php70\SpaceshipOperatorReplacer;
use Phabel\Target\Php70\StrictTypesDeclareStatementRemover;
use Phabel\Target\Php70\ThrowableReplacer;
@ -42,7 +42,7 @@ class Php70 extends Plugin
GroupUseReplacer::class,
NullCoalesceReplacer::class,
ReservedNameReplacer::class,
ScalarTypeHintsRemover::class,
ScalarTypeHints::class,
SpaceshipOperatorReplacer::class,
StrictTypesDeclareStatementRemover::class,
ThrowableReplacer::class,

View File

@ -9,7 +9,7 @@ use Phabel\Plugin\TypeHintStripper;
* @author Daniil Gentili <daniil@daniil.it>
* @license MIT
*/
class ScalarTypeHintsRemover extends Plugin
class ScalarTypeHints extends Plugin
{
/**
* Alias.

View File

@ -6,6 +6,7 @@ use Phabel\Plugin;
use Phabel\Target\Php71\ArrayList;
use Phabel\Target\Php71\ClassConstantVisibilityModifiersRemover;
use Phabel\Target\Php71\IssetExpressionFixer;
use Phabel\Target\Php71\IterableHint;
use Phabel\Target\Php71\ListKey;
use Phabel\Target\Php71\MultipleCatchReplacer;
use Phabel\Target\Php71\NestedExpressionFixer;
@ -32,6 +33,7 @@ class Php71 extends Plugin
ArrayList::class,
ClassConstantVisibilityModifiersRemover::class,
ListKey::class,
IterableHint::class,
MultipleCatchReplacer::class,
VoidReturnType::class,
NullableType::class

View File

@ -0,0 +1,27 @@
<?php
namespace Phabel\Target\Php71;
use Phabel\Plugin;
use Phabel\Plugin\TypeHintStripper;
/**
* @author Daniil Gentili <daniil@daniil.it>
* @license MIT
*/
class IterableHint extends Plugin
{
/**
* Alias.
*
* @return array
*/
public static function runAfter(): array
{
return [
TypeHintStripper::class => [
'types' => ['iterable']
]
];
}
}

View File

@ -0,0 +1,95 @@
<?php
namespace Phabel\Target\Php73;
use Phabel\Context;
use Phabel\Plugin;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\AssignRef;
use PhpParser\Node\Expr\List_;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Foreach_;
/**
* Polyfills list assignment by reference.
*/
class ListReference extends Plugin
{
/**
* Parse list foreach with custom keys.
*
* @param Foreach_ $node Foreach
*
* @return void
*/
public function enterForeach(Foreach_ $node, Context $ctx): void
{
if (!($node->valueVar instanceof List_ || $node->valueVar instanceof Array_) || !$this->shouldSplit($node->valueVar)) {
return;
}
$list = $node->valueVar;
$var = $node->valueVar = $ctx->getVariable();
$assignments = self::splitList($list, $var);
$node->stmts
}
/**
* Parse list assignment with custom keys.
*
* @param Assign $node List assignment
*
* @return void
*/
public function enterAssign(Assign $node, Context $ctx): void
{
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);
}
/**
* Split referenced list into multiple assignments.
*
* @param Array_|List_ $list List
* @param Variable $var Variable
*
* @return (Assign|AssignRef)[]
*/
private static function splitList($list, Variable $var): array
{
$assignments = [];
$key = 0; // Technically a list assignment does not support mixed keys, but we need this for nested assignments
foreach ($list->items as $item) {
if (!$item) {
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) {
$assignments []= new AssignRef($item->value, new ArrayDimFetch($var, $curKey));
} else {
$assignments []= new Assign($item->value, new ArrayDimFetch($var, $curKey));
}
}
return $assignments;
}
/**
* Whether this is a referenced list.
*
* @param List_|Array_ $list List
*
* @return boolean
*/
private function shouldSplit($list): bool
{
foreach ($list->items ?? [] as $item) {
if ($item->byRef) {
return true;
}
}
return false;
}
}