PluginProbe
WPIDE – File Manager & Code Editor / 3.5.9
WPIDE – File Manager & Code Editor v3.5.9
3.5.9 3.5.8 3.5.7 2.0.14 2.0.15 2.0.16 2.0.2 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1 2.2 2.3 2.3.1 2.3.2 2.4.0 2.5 2.6 3.0 3.1 3.2 3.3 All 55 releases
wpide / vendor / nikic / php-parser / lib / PhpParser / Internal / TokenStream.php

TokenStream.php in WPIDE – File Manager & Code Editor 3.5.9, at vendor/nikic/php-parser/lib/PhpParser/Internal/TokenStream.php

287 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php declare(strict_types=1);
2
3 namespace PhpParser\Internal;
4
5 /**
6 * Provides operations on token streams, for use by pretty printer.
7 *
8 * @internal
9 */
10 class TokenStream
11 {
12 /** @var array Tokens (in token_get_all format) */
13 private $tokens;
14 /** @var int[] Map from position to indentation */
15 private $indentMap;
16
17 /**
18 * Create token stream instance.
19 *
20 * @param array $tokens Tokens in token_get_all() format
21 */
22 public function __construct(array $tokens) {
23 $this->tokens = $tokens;
24 $this->indentMap = $this->calcIndentMap();
25 }
26
27 /**
28 * Whether the given position is immediately surrounded by parenthesis.
29 *
30 * @param int $startPos Start position
31 * @param int $endPos End position
32 *
33 * @return bool
34 */
35 public function haveParens(int $startPos, int $endPos) : bool {
36 return $this->haveTokenImmediatelyBefore($startPos, '(')
37 && $this->haveTokenImmediatelyAfter($endPos, ')');
38 }
39
40 /**
41 * Whether the given position is immediately surrounded by braces.
42 *
43 * @param int $startPos Start position
44 * @param int $endPos End position
45 *
46 * @return bool
47 */
48 public function haveBraces(int $startPos, int $endPos) : bool {
49 return ($this->haveTokenImmediatelyBefore($startPos, '{')
50 || $this->haveTokenImmediatelyBefore($startPos, T_CURLY_OPEN))
51 && $this->haveTokenImmediatelyAfter($endPos, '}');
52 }
53
54 /**
55 * Check whether the position is directly preceded by a certain token type.
56 *
57 * During this check whitespace and comments are skipped.
58 *
59 * @param int $pos Position before which the token should occur
60 * @param int|string $expectedTokenType Token to check for
61 *
62 * @return bool Whether the expected token was found
63 */
64 public function haveTokenImmediatelyBefore(int $pos, $expectedTokenType) : bool {
65 $tokens = $this->tokens;
66 $pos--;
67 for (; $pos >= 0; $pos--) {
68 $tokenType = $tokens[$pos][0];
69 if ($tokenType === $expectedTokenType) {
70 return true;
71 }
72 if ($tokenType !== \T_WHITESPACE
73 && $tokenType !== \T_COMMENT && $tokenType !== \T_DOC_COMMENT) {
74 break;
75 }
76 }
77 return false;
78 }
79
80 /**
81 * Check whether the position is directly followed by a certain token type.
82 *
83 * During this check whitespace and comments are skipped.
84 *
85 * @param int $pos Position after which the token should occur
86 * @param int|string $expectedTokenType Token to check for
87 *
88 * @return bool Whether the expected token was found
89 */
90 public function haveTokenImmediatelyAfter(int $pos, $expectedTokenType) : bool {
91 $tokens = $this->tokens;
92 $pos++;
93 for (; $pos < \count($tokens); $pos++) {
94 $tokenType = $tokens[$pos][0];
95 if ($tokenType === $expectedTokenType) {
96 return true;
97 }
98 if ($tokenType !== \T_WHITESPACE
99 && $tokenType !== \T_COMMENT && $tokenType !== \T_DOC_COMMENT) {
100 break;
101 }
102 }
103 return false;
104 }
105
106 public function skipLeft(int $pos, $skipTokenType) {
107 $tokens = $this->tokens;
108
109 $pos = $this->skipLeftWhitespace($pos);
110 if ($skipTokenType === \T_WHITESPACE) {
111 return $pos;
112 }
113
114 if ($tokens[$pos][0] !== $skipTokenType) {
115 // Shouldn't happen. The skip token MUST be there
116 throw new \Exception('Encountered unexpected token');
117 }
118 $pos--;
119
120 return $this->skipLeftWhitespace($pos);
121 }
122
123 public function skipRight(int $pos, $skipTokenType) {
124 $tokens = $this->tokens;
125
126 $pos = $this->skipRightWhitespace($pos);
127 if ($skipTokenType === \T_WHITESPACE) {
128 return $pos;
129 }
130
131 if ($tokens[$pos][0] !== $skipTokenType) {
132 // Shouldn't happen. The skip token MUST be there
133 throw new \Exception('Encountered unexpected token');
134 }
135 $pos++;
136
137 return $this->skipRightWhitespace($pos);
138 }
139
140 /**
141 * Return first non-whitespace token position smaller or equal to passed position.
142 *
143 * @param int $pos Token position
144 * @return int Non-whitespace token position
145 */
146 public function skipLeftWhitespace(int $pos) {
147 $tokens = $this->tokens;
148 for (; $pos >= 0; $pos--) {
149 $type = $tokens[$pos][0];
150 if ($type !== \T_WHITESPACE && $type !== \T_COMMENT && $type !== \T_DOC_COMMENT) {
151 break;
152 }
153 }
154 return $pos;
155 }
156
157 /**
158 * Return first non-whitespace position greater or equal to passed position.
159 *
160 * @param int $pos Token position
161 * @return int Non-whitespace token position
162 */
163 public function skipRightWhitespace(int $pos) {
164 $tokens = $this->tokens;
165 for ($count = \count($tokens); $pos < $count; $pos++) {
166 $type = $tokens[$pos][0];
167 if ($type !== \T_WHITESPACE && $type !== \T_COMMENT && $type !== \T_DOC_COMMENT) {
168 break;
169 }
170 }
171 return $pos;
172 }
173
174 public function findRight(int $pos, $findTokenType) {
175 $tokens = $this->tokens;
176 for ($count = \count($tokens); $pos < $count; $pos++) {
177 $type = $tokens[$pos][0];
178 if ($type === $findTokenType) {
179 return $pos;
180 }
181 }
182 return -1;
183 }
184
185 /**
186 * Whether the given position range contains a certain token type.
187 *
188 * @param int $startPos Starting position (inclusive)
189 * @param int $endPos Ending position (exclusive)
190 * @param int|string $tokenType Token type to look for
191 * @return bool Whether the token occurs in the given range
192 */
193 public function haveTokenInRange(int $startPos, int $endPos, $tokenType) {
194 $tokens = $this->tokens;
195 for ($pos = $startPos; $pos < $endPos; $pos++) {
196 if ($tokens[$pos][0] === $tokenType) {
197 return true;
198 }
199 }
200 return false;
201 }
202
203 public function haveBracesInRange(int $startPos, int $endPos) {
204 return $this->haveTokenInRange($startPos, $endPos, '{')
205 || $this->haveTokenInRange($startPos, $endPos, T_CURLY_OPEN)
206 || $this->haveTokenInRange($startPos, $endPos, '}');
207 }
208
209 public function haveTagInRange(int $startPos, int $endPos): bool {
210 return $this->haveTokenInRange($startPos, $endPos, \T_OPEN_TAG)
211 || $this->haveTokenInRange($startPos, $endPos, \T_CLOSE_TAG);
212 }
213
214 /**
215 * Get indentation before token position.
216 *
217 * @param int $pos Token position
218 *
219 * @return int Indentation depth (in spaces)
220 */
221 public function getIndentationBefore(int $pos) : int {
222 return $this->indentMap[$pos];
223 }
224
225 /**
226 * Get the code corresponding to a token offset range, optionally adjusted for indentation.
227 *
228 * @param int $from Token start position (inclusive)
229 * @param int $to Token end position (exclusive)
230 * @param int $indent By how much the code should be indented (can be negative as well)
231 *
232 * @return string Code corresponding to token range, adjusted for indentation
233 */
234 public function getTokenCode(int $from, int $to, int $indent) : string {
235 $tokens = $this->tokens;
236 $result = '';
237 for ($pos = $from; $pos < $to; $pos++) {
238 $token = $tokens[$pos];
239 if (\is_array($token)) {
240 $type = $token[0];
241 $content = $token[1];
242 if ($type === \T_CONSTANT_ENCAPSED_STRING || $type === \T_ENCAPSED_AND_WHITESPACE) {
243 $result .= $content;
244 } else {
245 // TODO Handle non-space indentation
246 if ($indent < 0) {
247 $result .= str_replace("\n" . str_repeat(" ", -$indent), "\n", $content);
248 } elseif ($indent > 0) {
249 $result .= str_replace("\n", "\n" . str_repeat(" ", $indent), $content);
250 } else {
251 $result .= $content;
252 }
253 }
254 } else {
255 $result .= $token;
256 }
257 }
258 return $result;
259 }
260
261 /**
262 * Precalculate the indentation at every token position.
263 *
264 * @return int[] Token position to indentation map
265 */
266 private function calcIndentMap() {
267 $indentMap = [];
268 $indent = 0;
269 foreach ($this->tokens as $token) {
270 $indentMap[] = $indent;
271
272 if ($token[0] === \T_WHITESPACE) {
273 $content = $token[1];
274 $newlinePos = \strrpos($content, "\n");
275 if (false !== $newlinePos) {
276 $indent = \strlen($content) - $newlinePos - 1;
277 }
278 }
279 }
280
281 // Add a sentinel for one past end of the file
282 $indentMap[] = $indent;
283
284 return $indentMap;
285 }
286 }
287