Skip to content

Commit

Permalink
Add support for array destructuring
Browse files Browse the repository at this point in the history
  • Loading branch information
sandrokeil committed Dec 2, 2018
1 parent d2959a8 commit 05c9b9f
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ $ php box.phar compile
$ docker-compose run --rm php vendor/bin/phpunit
```

## Zephir Docker Image

If you want to compile your Zephir zep files for PHP Alpine 3.8 Docker images try my [Zephir Docker images](https://github.com/sandrokeil/docker-files/tree/master/zephir).

## Limitations

Expand Down
50 changes: 50 additions & 0 deletions src/PhpParser/NodeVisitor/ArrayDestructuring.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
/**
* Sandro Keil (https://sandro-keil.de)
*
* @link http://github.com/sandrokeil/php-to-zephir for the canonical source repository
* @copyright Copyright (c) 2018 Sandro Keil
* @license http://github.com/sandrokeil/php-to-zephir/blob/master/LICENSE.md New BSD License
*/
declare(strict_types=1);

namespace PhpToZephir\PhpParser\NodeVisitor;

use PhpParser\NodeVisitorAbstract;
use PhpParser\Node;

class ArrayDestructuring extends NodeVisitorAbstract
{
public function leaveNode(Node $node)
{
if ($node instanceof Node\Stmt\Expression
&& $node->expr instanceof Node\Expr\Assign
&& $node->expr->expr instanceof Node\Expr\Array_
&& $node->expr->var instanceof Node\Expr\Array_
) {
$stmts = array_map(function (Node\Expr\ArrayItem $item) {
return new Node\Expr\Variable($item->value->name);
}, $node->expr->var->items);

$arrayName = bin2hex(random_bytes(6));
$key = -1;
$destructuring = array_map(function (Node\Expr\ArrayItem $item) use ($stmts, $arrayName, &$key) {
$key++;
$name = clone $stmts[$key];
$name->setAttribute('init', false);
return new Node\Expr\Assign($name, new Node\Expr\ArrayDimFetch(
new Node\Expr\Variable($arrayName, $item->getAttributes()),
new Node\Scalar\LNumber($key)
));
}, $node->expr->var->items);

$node->expr->var = new Node\Expr\Variable($arrayName, $node->getAttributes());

$stmts[] = $node;

$stmts = array_merge($stmts, $destructuring);

return $stmts;
}
}
}
1 change: 1 addition & 0 deletions src/ZephirPrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use PhpParser\Node\Stmt;
use PhpParser\Node\Expr\AssignOp;
use PhpParser\Node\Expr\BinaryOp;
use PhpToZephir\PhpParser\NodeVisitor\InitLocalVariable;

/**
* Zephir Printer
Expand Down
29 changes: 29 additions & 0 deletions test/ZephirPrinterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

use PhpParser\ParserFactory;
use PhpParser\NodeTraverser;
use PhpToZephir\PhpParser\NodeVisitor\ArrayDestructuring;
use PhpToZephir\PhpParser\NodeVisitor\InitLocalVariable;
use PhpToZephir\PhpParser\NodeVisitor\RemoveUseFunction;
use PhpToZephir\PhpParser\NodeVisitor\UnsetSplitter;
Expand Down Expand Up @@ -42,6 +43,7 @@ protected function setUp()
$this->traverser->addVisitor(new InitLocalVariable());
$this->traverser->addVisitor(new RemoveUseFunction());
$this->traverser->addVisitor(new UnsetSplitter());
$this->traverser->addVisitor(new ArrayDestructuring());
$this->zephirPrinter = new ZephirPrinter();
}

Expand Down Expand Up @@ -452,4 +454,31 @@ public function it_converts_unset(): void

$this->assertEquals($expectedCode, $current, $current);
}

/**
* @test
*/
public function it_converts_array_destructuring(): void
{
$code = <<<'CODE'
<?php
[$firstName, $lastName] = ["John", "Doe"];
CODE;

$ast = $this->parser->parse($code);
$ast = $this->traverser->traverse($ast);
$current = $this->zephirPrinter->prettyPrintFile($ast);

/**
* var firstName;
* var lastName;
* let db5910704831 = ["John", "Doe"];
* let firstName = db5910704831[0]
* let lastName = db5910704831[1]
*/
$this->assertTrue(strpos($current, 'var firstName;') !== false, $current);
$this->assertTrue(strpos($current, 'var lastName;') !== false, $current);
$this->assertTrue(strpos($current, 'let firstName = ') !== false, $current);
$this->assertTrue(strpos($current, 'let lastName = ') !== false, $current);
}
}

0 comments on commit 05c9b9f

Please sign in to comment.