Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Details | Vergleich mit vorheriger | 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
 *
200 lars 6
 * (c) 2012-2023 Justin Hileman
148 lars 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\FunctionLike;
16
use PhpParser\Node\Stmt\Goto_;
17
use PhpParser\Node\Stmt\Label;
18
use Psy\Exception\FatalErrorException;
19
 
20
/**
21
 * CodeCleanerPass for label context.
22
 *
23
 * This class partially emulates the PHP label specification.
24
 * PsySH can not declare labels by sequentially executing lines with eval,
25
 * but since it is not a syntax error, no error is raised.
26
 * This class warns before invalid goto causes a fatal error.
27
 * Since this is a simple checker, it does not block real fatal error
28
 * with complex syntax.  (ex. it does not parse inside function.)
29
 *
30
 * @see http://php.net/goto
31
 */
32
class LabelContextPass extends CodeCleanerPass
33
{
34
    /** @var int */
35
    private $functionDepth;
36
 
37
    /** @var array */
38
    private $labelDeclarations;
39
    /** @var array */
40
    private $labelGotos;
41
 
42
    /**
43
     * @param array $nodes
44
     *
45
     * @return Node[]|null Array of nodes
46
     */
47
    public function beforeTraverse(array $nodes)
48
    {
49
        $this->functionDepth = 0;
50
        $this->labelDeclarations = [];
51
        $this->labelGotos = [];
52
    }
53
 
54
    /**
55
     * @return int|Node|null Replacement node (or special return value)
56
     */
57
    public function enterNode(Node $node)
58
    {
59
        if ($node instanceof FunctionLike) {
60
            $this->functionDepth++;
61
 
62
            return;
63
        }
64
 
65
        // node is inside function context
66
        if ($this->functionDepth !== 0) {
67
            return;
68
        }
69
 
70
        if ($node instanceof Goto_) {
71
            $this->labelGotos[\strtolower($node->name)] = $node->getLine();
72
        } elseif ($node instanceof Label) {
73
            $this->labelDeclarations[\strtolower($node->name)] = $node->getLine();
74
        }
75
    }
76
 
77
    /**
78
     * @param \PhpParser\Node $node
79
     *
80
     * @return int|Node|Node[]|null Replacement node (or special return value)
81
     */
82
    public function leaveNode(Node $node)
83
    {
84
        if ($node instanceof FunctionLike) {
85
            $this->functionDepth--;
86
        }
87
    }
88
 
89
    /**
90
     * @return Node[]|null Array of nodes
91
     */
92
    public function afterTraverse(array $nodes)
93
    {
94
        foreach ($this->labelGotos as $name => $line) {
95
            if (!isset($this->labelDeclarations[$name])) {
96
                $msg = "'goto' to undefined label '{$name}'";
97
                throw new FatalErrorException($msg, 0, \E_ERROR, null, $line);
98
            }
99
        }
100
    }
101
}