Chris@16
|
1 <?php
|
Chris@16
|
2
|
Chris@16
|
3 /*
|
Chris@16
|
4 * This file is part of Psy Shell.
|
Chris@16
|
5 *
|
Chris@16
|
6 * (c) 2012-2018 Justin Hileman
|
Chris@16
|
7 *
|
Chris@16
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@16
|
9 * file that was distributed with this source code.
|
Chris@16
|
10 */
|
Chris@16
|
11
|
Chris@16
|
12 namespace Psy\CodeCleaner;
|
Chris@16
|
13
|
Chris@16
|
14 use PhpParser\Node;
|
Chris@16
|
15 use PhpParser\Node\Expr\Array_;
|
Chris@16
|
16 use PhpParser\Node\Expr\ArrayItem;
|
Chris@16
|
17 use PhpParser\Node\Expr\Assign;
|
Chris@16
|
18 use PhpParser\Node\Expr\List_;
|
Chris@16
|
19 use PhpParser\Node\Expr\Variable;
|
Chris@16
|
20 use Psy\Exception\ParseErrorException;
|
Chris@16
|
21
|
Chris@16
|
22 /**
|
Chris@16
|
23 * Validate that the list assignment.
|
Chris@16
|
24 */
|
Chris@16
|
25 class ListPass extends CodeCleanerPass
|
Chris@16
|
26 {
|
Chris@16
|
27 private $atLeastPhp71;
|
Chris@16
|
28
|
Chris@16
|
29 public function __construct()
|
Chris@16
|
30 {
|
Chris@16
|
31 $this->atLeastPhp71 = version_compare(PHP_VERSION, '7.1', '>=');
|
Chris@16
|
32 }
|
Chris@16
|
33
|
Chris@16
|
34 /**
|
Chris@16
|
35 * Validate use of list assignment.
|
Chris@16
|
36 *
|
Chris@16
|
37 * @throws ParseErrorException if the user used empty with anything but a variable
|
Chris@16
|
38 *
|
Chris@16
|
39 * @param Node $node
|
Chris@16
|
40 */
|
Chris@16
|
41 public function enterNode(Node $node)
|
Chris@16
|
42 {
|
Chris@16
|
43 if (!$node instanceof Assign) {
|
Chris@16
|
44 return;
|
Chris@16
|
45 }
|
Chris@16
|
46
|
Chris@16
|
47 if (!$node->var instanceof Array_ && !$node->var instanceof List_) {
|
Chris@16
|
48 return;
|
Chris@16
|
49 }
|
Chris@16
|
50
|
Chris@16
|
51 if (!$this->atLeastPhp71 && $node->var instanceof Array_) {
|
Chris@16
|
52 $msg = "syntax error, unexpected '='";
|
Chris@16
|
53 throw new ParseErrorException($msg, $node->expr->getLine());
|
Chris@16
|
54 }
|
Chris@16
|
55
|
Chris@16
|
56 // Polyfill for PHP-Parser 2.x
|
Chris@16
|
57 $items = isset($node->var->items) ? $node->var->items : $node->var->vars;
|
Chris@16
|
58
|
Chris@16
|
59 if ($items === [] || $items === [null]) {
|
Chris@16
|
60 throw new ParseErrorException('Cannot use empty list', $node->var->getLine());
|
Chris@16
|
61 }
|
Chris@16
|
62
|
Chris@16
|
63 $itemFound = false;
|
Chris@16
|
64 foreach ($items as $item) {
|
Chris@16
|
65 if ($item === null) {
|
Chris@16
|
66 continue;
|
Chris@16
|
67 }
|
Chris@16
|
68
|
Chris@16
|
69 $itemFound = true;
|
Chris@16
|
70
|
Chris@16
|
71 // List_->$vars in PHP-Parser 2.x is Variable instead of ArrayItem.
|
Chris@16
|
72 if (!$this->atLeastPhp71 && $item instanceof ArrayItem && $item->key !== null) {
|
Chris@16
|
73 $msg = 'Syntax error, unexpected T_CONSTANT_ENCAPSED_STRING, expecting \',\' or \')\'';
|
Chris@16
|
74 throw new ParseErrorException($msg, $item->key->getLine());
|
Chris@16
|
75 }
|
Chris@16
|
76
|
Chris@16
|
77 $value = ($item instanceof ArrayItem) ? $item->value : $item;
|
Chris@16
|
78
|
Chris@16
|
79 if (!$value instanceof Variable) {
|
Chris@16
|
80 $msg = 'Assignments can only happen to writable values';
|
Chris@16
|
81 throw new ParseErrorException($msg, $item->getLine());
|
Chris@16
|
82 }
|
Chris@16
|
83 }
|
Chris@16
|
84
|
Chris@16
|
85 if (!$itemFound) {
|
Chris@16
|
86 throw new ParseErrorException('Cannot use empty list');
|
Chris@16
|
87 }
|
Chris@16
|
88 }
|
Chris@16
|
89 }
|