annotate vendor/psy/psysh/src/CodeCleaner/ListPass.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
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@17 15 use PhpParser\Node\Expr;
Chris@16 16 use PhpParser\Node\Expr\Array_;
Chris@17 17 use PhpParser\Node\Expr\ArrayDimFetch;
Chris@16 18 use PhpParser\Node\Expr\ArrayItem;
Chris@16 19 use PhpParser\Node\Expr\Assign;
Chris@17 20 use PhpParser\Node\Expr\FuncCall;
Chris@16 21 use PhpParser\Node\Expr\List_;
Chris@17 22 use PhpParser\Node\Expr\MethodCall;
Chris@17 23 use PhpParser\Node\Expr\PropertyFetch;
Chris@16 24 use PhpParser\Node\Expr\Variable;
Chris@16 25 use Psy\Exception\ParseErrorException;
Chris@16 26
Chris@16 27 /**
Chris@16 28 * Validate that the list assignment.
Chris@16 29 */
Chris@16 30 class ListPass extends CodeCleanerPass
Chris@16 31 {
Chris@16 32 private $atLeastPhp71;
Chris@16 33
Chris@16 34 public function __construct()
Chris@16 35 {
Chris@17 36 $this->atLeastPhp71 = \version_compare(PHP_VERSION, '7.1', '>=');
Chris@16 37 }
Chris@16 38
Chris@16 39 /**
Chris@16 40 * Validate use of list assignment.
Chris@16 41 *
Chris@16 42 * @throws ParseErrorException if the user used empty with anything but a variable
Chris@16 43 *
Chris@16 44 * @param Node $node
Chris@16 45 */
Chris@16 46 public function enterNode(Node $node)
Chris@16 47 {
Chris@16 48 if (!$node instanceof Assign) {
Chris@16 49 return;
Chris@16 50 }
Chris@16 51
Chris@16 52 if (!$node->var instanceof Array_ && !$node->var instanceof List_) {
Chris@16 53 return;
Chris@16 54 }
Chris@16 55
Chris@16 56 if (!$this->atLeastPhp71 && $node->var instanceof Array_) {
Chris@16 57 $msg = "syntax error, unexpected '='";
Chris@16 58 throw new ParseErrorException($msg, $node->expr->getLine());
Chris@16 59 }
Chris@16 60
Chris@16 61 // Polyfill for PHP-Parser 2.x
Chris@16 62 $items = isset($node->var->items) ? $node->var->items : $node->var->vars;
Chris@16 63
Chris@16 64 if ($items === [] || $items === [null]) {
Chris@16 65 throw new ParseErrorException('Cannot use empty list', $node->var->getLine());
Chris@16 66 }
Chris@16 67
Chris@16 68 $itemFound = false;
Chris@16 69 foreach ($items as $item) {
Chris@16 70 if ($item === null) {
Chris@16 71 continue;
Chris@16 72 }
Chris@16 73
Chris@16 74 $itemFound = true;
Chris@16 75
Chris@16 76 // List_->$vars in PHP-Parser 2.x is Variable instead of ArrayItem.
Chris@16 77 if (!$this->atLeastPhp71 && $item instanceof ArrayItem && $item->key !== null) {
Chris@16 78 $msg = 'Syntax error, unexpected T_CONSTANT_ENCAPSED_STRING, expecting \',\' or \')\'';
Chris@16 79 throw new ParseErrorException($msg, $item->key->getLine());
Chris@16 80 }
Chris@16 81
Chris@17 82 if (!self::isValidArrayItem($item)) {
Chris@16 83 $msg = 'Assignments can only happen to writable values';
Chris@16 84 throw new ParseErrorException($msg, $item->getLine());
Chris@16 85 }
Chris@16 86 }
Chris@16 87
Chris@16 88 if (!$itemFound) {
Chris@16 89 throw new ParseErrorException('Cannot use empty list');
Chris@16 90 }
Chris@16 91 }
Chris@17 92
Chris@17 93 /**
Chris@17 94 * Validate whether a given item in an array is valid for short assignment.
Chris@17 95 *
Chris@17 96 * @param Expr $item
Chris@17 97 *
Chris@17 98 * @return bool
Chris@17 99 */
Chris@17 100 private static function isValidArrayItem(Expr $item)
Chris@17 101 {
Chris@17 102 $value = ($item instanceof ArrayItem) ? $item->value : $item;
Chris@17 103
Chris@17 104 while ($value instanceof ArrayDimFetch || $value instanceof PropertyFetch) {
Chris@17 105 $value = $value->var;
Chris@17 106 }
Chris@17 107
Chris@17 108 // We just kind of give up if it's a method call. We can't tell if it's
Chris@17 109 // valid via static analysis.
Chris@17 110 return $value instanceof Variable || $value instanceof MethodCall || $value instanceof FuncCall;
Chris@17 111 }
Chris@16 112 }