Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / vendor / psy / psysh / src / CodeCleaner / LoopContextPass.php
1 <?php
2
3 /*
4  * This file is part of Psy Shell.
5  *
6  * (c) 2012-2018 Justin Hileman
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Psy\CodeCleaner;
13
14 use PhpParser\Node;
15 use PhpParser\Node\Scalar\DNumber;
16 use PhpParser\Node\Scalar\LNumber;
17 use PhpParser\Node\Stmt\Break_;
18 use PhpParser\Node\Stmt\Continue_;
19 use PhpParser\Node\Stmt\Do_;
20 use PhpParser\Node\Stmt\For_;
21 use PhpParser\Node\Stmt\Foreach_;
22 use PhpParser\Node\Stmt\Switch_;
23 use PhpParser\Node\Stmt\While_;
24 use Psy\Exception\FatalErrorException;
25
26 /**
27  * The loop context pass handles invalid `break` and `continue` statements.
28  */
29 class LoopContextPass extends CodeCleanerPass
30 {
31     private $loopDepth;
32
33     /**
34      * {@inheritdoc}
35      */
36     public function beforeTraverse(array $nodes)
37     {
38         $this->loopDepth = 0;
39     }
40
41     /**
42      * @throws FatalErrorException if the node is a break or continue in a non-loop or switch context
43      * @throws FatalErrorException if the node is trying to break out of more nested structures than exist
44      * @throws FatalErrorException if the node is a break or continue and has a non-numeric argument
45      * @throws FatalErrorException if the node is a break or continue and has an argument less than 1
46      *
47      * @param Node $node
48      */
49     public function enterNode(Node $node)
50     {
51         switch (true) {
52             case $node instanceof Do_:
53             case $node instanceof For_:
54             case $node instanceof Foreach_:
55             case $node instanceof Switch_:
56             case $node instanceof While_:
57                 $this->loopDepth++;
58                 break;
59
60             case $node instanceof Break_:
61             case $node instanceof Continue_:
62                 $operator = $node instanceof Break_ ? 'break' : 'continue';
63
64                 if ($this->loopDepth === 0) {
65                     $msg = sprintf("'%s' not in the 'loop' or 'switch' context", $operator);
66                     throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
67                 }
68
69                 if ($node->num instanceof LNumber || $node->num instanceof DNumber) {
70                     $num = $node->num->value;
71                     if ($node->num instanceof DNumber || $num < 1) {
72                         $msg = sprintf("'%s' operator accepts only positive numbers", $operator);
73                         throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
74                     }
75
76                     if ($num > $this->loopDepth) {
77                         $msg = sprintf("Cannot '%s' %d levels", $operator, $num);
78                         throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
79                     }
80                 } elseif ($node->num) {
81                     $msg = sprintf("'%s' operator with non-constant operand is no longer supported", $operator);
82                     throw new FatalErrorException($msg, 0, E_ERROR, null, $node->getLine());
83                 }
84                 break;
85         }
86     }
87
88     /**
89      * @param Node $node
90      */
91     public function leaveNode(Node $node)
92     {
93         switch (true) {
94             case $node instanceof Do_:
95             case $node instanceof For_:
96             case $node instanceof Foreach_:
97             case $node instanceof Switch_:
98             case $node instanceof While_:
99                 $this->loopDepth--;
100                 break;
101         }
102     }
103 }