Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/*
4
 * This file is part of Psy Shell.
5
 *
6
 * (c) 2012-2022 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
     * @return Node[]|null Array of nodes
37
     */
38
    public function beforeTraverse(array $nodes)
39
    {
40
        $this->loopDepth = 0;
41
    }
42
 
43
    /**
44
     * @throws FatalErrorException if the node is a break or continue in a non-loop or switch context
45
     * @throws FatalErrorException if the node is trying to break out of more nested structures than exist
46
     * @throws FatalErrorException if the node is a break or continue and has a non-numeric argument
47
     * @throws FatalErrorException if the node is a break or continue and has an argument less than 1
48
     *
49
     * @param Node $node
50
     *
51
     * @return int|Node|null Replacement node (or special return value)
52
     */
53
    public function enterNode(Node $node)
54
    {
55
        switch (true) {
56
            case $node instanceof Do_:
57
            case $node instanceof For_:
58
            case $node instanceof Foreach_:
59
            case $node instanceof Switch_:
60
            case $node instanceof While_:
61
                $this->loopDepth++;
62
                break;
63
 
64
            case $node instanceof Break_:
65
            case $node instanceof Continue_:
66
                $operator = $node instanceof Break_ ? 'break' : 'continue';
67
 
68
                if ($this->loopDepth === 0) {
69
                    $msg = \sprintf("'%s' not in the 'loop' or 'switch' context", $operator);
70
                    throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
71
                }
72
 
73
                if ($node->num instanceof LNumber || $node->num instanceof DNumber) {
74
                    $num = $node->num->value;
75
                    if ($node->num instanceof DNumber || $num < 1) {
76
                        $msg = \sprintf("'%s' operator accepts only positive numbers", $operator);
77
                        throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
78
                    }
79
 
80
                    if ($num > $this->loopDepth) {
81
                        $msg = \sprintf("Cannot '%s' %d levels", $operator, $num);
82
                        throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
83
                    }
84
                } elseif ($node->num) {
85
                    $msg = \sprintf("'%s' operator with non-constant operand is no longer supported", $operator);
86
                    throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getLine());
87
                }
88
                break;
89
        }
90
    }
91
 
92
    /**
93
     * @param Node $node
94
     *
95
     * @return int|Node|Node[]|null Replacement node (or special return value)
96
     */
97
    public function leaveNode(Node $node)
98
    {
99
        switch (true) {
100
            case $node instanceof Do_:
101
            case $node instanceof For_:
102
            case $node instanceof Foreach_:
103
            case $node instanceof Switch_:
104
            case $node instanceof While_:
105
                $this->loopDepth--;
106
                break;
107
        }
108
    }
109
}