Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php declare(strict_types=1);
2
 
3
namespace PhpParser;
4
 
5
use PhpParser\Node\Expr\Include_;
6
use PhpParser\Node\Stmt\Class_;
7
use PhpParser\Node\Stmt\GroupUse;
8
use PhpParser\Node\Stmt\Use_;
9
use PhpParser\Node\Stmt\UseUse;
10
 
11
class NodeDumper
12
{
13
    private $dumpComments;
14
    private $dumpPositions;
15
    private $code;
16
 
17
    /**
18
     * Constructs a NodeDumper.
19
     *
20
     * Supported options:
21
     *  * bool dumpComments: Whether comments should be dumped.
22
     *  * bool dumpPositions: Whether line/offset information should be dumped. To dump offset
23
     *                        information, the code needs to be passed to dump().
24
     *
25
     * @param array $options Options (see description)
26
     */
27
    public function __construct(array $options = []) {
28
        $this->dumpComments = !empty($options['dumpComments']);
29
        $this->dumpPositions = !empty($options['dumpPositions']);
30
    }
31
 
32
    /**
33
     * Dumps a node or array.
34
     *
35
     * @param array|Node  $node Node or array to dump
36
     * @param string|null $code Code corresponding to dumped AST. This only needs to be passed if
37
     *                          the dumpPositions option is enabled and the dumping of node offsets
38
     *                          is desired.
39
     *
40
     * @return string Dumped value
41
     */
42
    public function dump($node, string $code = null) : string {
43
        $this->code = $code;
44
        return $this->dumpRecursive($node);
45
    }
46
 
47
    protected function dumpRecursive($node) {
48
        if ($node instanceof Node) {
49
            $r = $node->getType();
50
            if ($this->dumpPositions && null !== $p = $this->dumpPosition($node)) {
51
                $r .= $p;
52
            }
53
            $r .= '(';
54
 
55
            foreach ($node->getSubNodeNames() as $key) {
56
                $r .= "\n    " . $key . ': ';
57
 
58
                $value = $node->$key;
59
                if (null === $value) {
60
                    $r .= 'null';
61
                } elseif (false === $value) {
62
                    $r .= 'false';
63
                } elseif (true === $value) {
64
                    $r .= 'true';
65
                } elseif (is_scalar($value)) {
66
                    if ('flags' === $key || 'newModifier' === $key) {
67
                        $r .= $this->dumpFlags($value);
68
                    } elseif ('type' === $key && $node instanceof Include_) {
69
                        $r .= $this->dumpIncludeType($value);
70
                    } elseif ('type' === $key
71
                            && ($node instanceof Use_ || $node instanceof UseUse || $node instanceof GroupUse)) {
72
                        $r .= $this->dumpUseType($value);
73
                    } else {
74
                        $r .= $value;
75
                    }
76
                } else {
77
                    $r .= str_replace("\n", "\n    ", $this->dumpRecursive($value));
78
                }
79
            }
80
 
81
            if ($this->dumpComments && $comments = $node->getComments()) {
82
                $r .= "\n    comments: " . str_replace("\n", "\n    ", $this->dumpRecursive($comments));
83
            }
84
        } elseif (is_array($node)) {
85
            $r = 'array(';
86
 
87
            foreach ($node as $key => $value) {
88
                $r .= "\n    " . $key . ': ';
89
 
90
                if (null === $value) {
91
                    $r .= 'null';
92
                } elseif (false === $value) {
93
                    $r .= 'false';
94
                } elseif (true === $value) {
95
                    $r .= 'true';
96
                } elseif (is_scalar($value)) {
97
                    $r .= $value;
98
                } else {
99
                    $r .= str_replace("\n", "\n    ", $this->dumpRecursive($value));
100
                }
101
            }
102
        } elseif ($node instanceof Comment) {
103
            return $node->getReformattedText();
104
        } else {
105
            throw new \InvalidArgumentException('Can only dump nodes and arrays.');
106
        }
107
 
108
        return $r . "\n)";
109
    }
110
 
111
    protected function dumpFlags($flags) {
112
        $strs = [];
113
        if ($flags & Class_::MODIFIER_PUBLIC) {
114
            $strs[] = 'MODIFIER_PUBLIC';
115
        }
116
        if ($flags & Class_::MODIFIER_PROTECTED) {
117
            $strs[] = 'MODIFIER_PROTECTED';
118
        }
119
        if ($flags & Class_::MODIFIER_PRIVATE) {
120
            $strs[] = 'MODIFIER_PRIVATE';
121
        }
122
        if ($flags & Class_::MODIFIER_ABSTRACT) {
123
            $strs[] = 'MODIFIER_ABSTRACT';
124
        }
125
        if ($flags & Class_::MODIFIER_STATIC) {
126
            $strs[] = 'MODIFIER_STATIC';
127
        }
128
        if ($flags & Class_::MODIFIER_FINAL) {
129
            $strs[] = 'MODIFIER_FINAL';
130
        }
131
        if ($flags & Class_::MODIFIER_READONLY) {
132
            $strs[] = 'MODIFIER_READONLY';
133
        }
134
 
135
        if ($strs) {
136
            return implode(' | ', $strs) . ' (' . $flags . ')';
137
        } else {
138
            return $flags;
139
        }
140
    }
141
 
142
    protected function dumpIncludeType($type) {
143
        $map = [
144
            Include_::TYPE_INCLUDE      => 'TYPE_INCLUDE',
145
            Include_::TYPE_INCLUDE_ONCE => 'TYPE_INCLUDE_ONCE',
146
            Include_::TYPE_REQUIRE      => 'TYPE_REQUIRE',
147
            Include_::TYPE_REQUIRE_ONCE => 'TYPE_REQUIRE_ONCE',
148
        ];
149
 
150
        if (!isset($map[$type])) {
151
            return $type;
152
        }
153
        return $map[$type] . ' (' . $type . ')';
154
    }
155
 
156
    protected function dumpUseType($type) {
157
        $map = [
158
            Use_::TYPE_UNKNOWN  => 'TYPE_UNKNOWN',
159
            Use_::TYPE_NORMAL   => 'TYPE_NORMAL',
160
            Use_::TYPE_FUNCTION => 'TYPE_FUNCTION',
161
            Use_::TYPE_CONSTANT => 'TYPE_CONSTANT',
162
        ];
163
 
164
        if (!isset($map[$type])) {
165
            return $type;
166
        }
167
        return $map[$type] . ' (' . $type . ')';
168
    }
169
 
170
    /**
171
     * Dump node position, if possible.
172
     *
173
     * @param Node $node Node for which to dump position
174
     *
175
     * @return string|null Dump of position, or null if position information not available
176
     */
177
    protected function dumpPosition(Node $node) {
178
        if (!$node->hasAttribute('startLine') || !$node->hasAttribute('endLine')) {
179
            return null;
180
        }
181
 
182
        $start = $node->getStartLine();
183
        $end = $node->getEndLine();
184
        if ($node->hasAttribute('startFilePos') && $node->hasAttribute('endFilePos')
185
            && null !== $this->code
186
        ) {
187
            $start .= ':' . $this->toColumn($this->code, $node->getStartFilePos());
188
            $end .= ':' . $this->toColumn($this->code, $node->getEndFilePos());
189
        }
190
        return "[$start - $end]";
191
    }
192
 
193
    // Copied from Error class
194
    private function toColumn($code, $pos) {
195
        if ($pos > strlen($code)) {
196
            throw new \RuntimeException('Invalid position information');
197
        }
198
 
199
        $lineStartPos = strrpos($code, "\n", $pos - strlen($code));
200
        if (false === $lineStartPos) {
201
            $lineStartPos = -1;
202
        }
203
 
204
        return $pos - $lineStartPos;
205
    }
206
}