Mercurial > hg > isophonics-drupal-site
comparison vendor/nikic/php-parser/lib/PhpParser/Internal/TokenStream.php @ 13:5fb285c0d0e3
Update Drupal core to 8.4.7 via Composer. Security update; I *think* we've
been lucky to get away with this so far, as we don't support self-registration
which seems to be used by the so-called "drupalgeddon 2" attack that 8.4.5
was vulnerable to.
author | Chris Cannam |
---|---|
date | Mon, 23 Apr 2018 09:33:26 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
12:7a779792577d | 13:5fb285c0d0e3 |
---|---|
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->haveTokenImmediativelyBefore($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->haveTokenImmediativelyBefore($startPos, '{') | |
50 && $this->haveTokenImmediatelyAfter($endPos, '}'); | |
51 } | |
52 | |
53 /** | |
54 * Check whether the position is directly preceded by a certain token type. | |
55 * | |
56 * During this check whitespace and comments are skipped. | |
57 * | |
58 * @param int $pos Position before which the token should occur | |
59 * @param int|string $expectedTokenType Token to check for | |
60 * | |
61 * @return bool Whether the expected token was found | |
62 */ | |
63 public function haveTokenImmediativelyBefore(int $pos, $expectedTokenType) : bool { | |
64 $tokens = $this->tokens; | |
65 $pos--; | |
66 for (; $pos >= 0; $pos--) { | |
67 $tokenType = $tokens[$pos][0]; | |
68 if ($tokenType === $expectedTokenType) { | |
69 return true; | |
70 } | |
71 if ($tokenType !== \T_WHITESPACE | |
72 && $tokenType !== \T_COMMENT && $tokenType !== \T_DOC_COMMENT) { | |
73 break; | |
74 } | |
75 } | |
76 return false; | |
77 } | |
78 | |
79 /** | |
80 * Check whether the position is directly followed by a certain token type. | |
81 * | |
82 * During this check whitespace and comments are skipped. | |
83 * | |
84 * @param int $pos Position after which the token should occur | |
85 * @param int|string $expectedTokenType Token to check for | |
86 * | |
87 * @return bool Whether the expected token was found | |
88 */ | |
89 public function haveTokenImmediatelyAfter(int $pos, $expectedTokenType) : bool { | |
90 $tokens = $this->tokens; | |
91 $pos++; | |
92 for (; $pos < \count($tokens); $pos++) { | |
93 $tokenType = $tokens[$pos][0]; | |
94 if ($tokenType === $expectedTokenType) { | |
95 return true; | |
96 } | |
97 if ($tokenType !== \T_WHITESPACE | |
98 && $tokenType !== \T_COMMENT && $tokenType !== \T_DOC_COMMENT) { | |
99 break; | |
100 } | |
101 } | |
102 return false; | |
103 } | |
104 | |
105 public function skipLeft(int $pos, $skipTokenType) { | |
106 $tokens = $this->tokens; | |
107 | |
108 $pos = $this->skipLeftWhitespace($pos); | |
109 if ($skipTokenType === \T_WHITESPACE) { | |
110 return $pos; | |
111 } | |
112 | |
113 if ($tokens[$pos][0] !== $skipTokenType) { | |
114 // Shouldn't happen. The skip token MUST be there | |
115 throw new \Exception('Encountered unexpected token'); | |
116 } | |
117 $pos--; | |
118 | |
119 return $this->skipLeftWhitespace($pos); | |
120 } | |
121 | |
122 public function skipRight(int $pos, $skipTokenType) { | |
123 $tokens = $this->tokens; | |
124 | |
125 $pos = $this->skipRightWhitespace($pos); | |
126 if ($skipTokenType === \T_WHITESPACE) { | |
127 return $pos; | |
128 } | |
129 | |
130 if ($tokens[$pos][0] !== $skipTokenType) { | |
131 // Shouldn't happen. The skip token MUST be there | |
132 throw new \Exception('Encountered unexpected token'); | |
133 } | |
134 $pos++; | |
135 | |
136 return $this->skipRightWhitespace($pos); | |
137 } | |
138 | |
139 /** | |
140 * Return first non-whitespace token position smaller or equal to passed position. | |
141 * | |
142 * @param int $pos Token position | |
143 * @return int Non-whitespace token position | |
144 */ | |
145 public function skipLeftWhitespace(int $pos) { | |
146 $tokens = $this->tokens; | |
147 for (; $pos >= 0; $pos--) { | |
148 $type = $tokens[$pos][0]; | |
149 if ($type !== \T_WHITESPACE && $type !== \T_COMMENT && $type !== \T_DOC_COMMENT) { | |
150 break; | |
151 } | |
152 } | |
153 return $pos; | |
154 } | |
155 | |
156 /** | |
157 * Return first non-whitespace position greater or equal to passed position. | |
158 * | |
159 * @param int $pos Token position | |
160 * @return int Non-whitespace token position | |
161 */ | |
162 public function skipRightWhitespace(int $pos) { | |
163 $tokens = $this->tokens; | |
164 for ($count = \count($tokens); $pos < $count; $pos++) { | |
165 $type = $tokens[$pos][0]; | |
166 if ($type !== \T_WHITESPACE && $type !== \T_COMMENT && $type !== \T_DOC_COMMENT) { | |
167 break; | |
168 } | |
169 } | |
170 return $pos; | |
171 } | |
172 | |
173 public function findRight($pos, $findTokenType) { | |
174 $tokens = $this->tokens; | |
175 for ($count = \count($tokens); $pos < $count; $pos++) { | |
176 $type = $tokens[$pos][0]; | |
177 if ($type === $findTokenType) { | |
178 return $pos; | |
179 } | |
180 } | |
181 return -1; | |
182 } | |
183 | |
184 /** | |
185 * Get indentation before token position. | |
186 * | |
187 * @param int $pos Token position | |
188 * | |
189 * @return int Indentation depth (in spaces) | |
190 */ | |
191 public function getIndentationBefore(int $pos) : int { | |
192 return $this->indentMap[$pos]; | |
193 } | |
194 | |
195 /** | |
196 * Get the code corresponding to a token offset range, optionally adjusted for indentation. | |
197 * | |
198 * @param int $from Token start position (inclusive) | |
199 * @param int $to Token end position (exclusive) | |
200 * @param int $indent By how much the code should be indented (can be negative as well) | |
201 * | |
202 * @return string Code corresponding to token range, adjusted for indentation | |
203 */ | |
204 public function getTokenCode(int $from, int $to, int $indent) : string { | |
205 $tokens = $this->tokens; | |
206 $result = ''; | |
207 for ($pos = $from; $pos < $to; $pos++) { | |
208 $token = $tokens[$pos]; | |
209 if (\is_array($token)) { | |
210 $type = $token[0]; | |
211 $content = $token[1]; | |
212 if ($type === \T_CONSTANT_ENCAPSED_STRING || $type === \T_ENCAPSED_AND_WHITESPACE) { | |
213 $result .= $content; | |
214 } else { | |
215 // TODO Handle non-space indentation | |
216 if ($indent < 0) { | |
217 $result .= str_replace("\n" . str_repeat(" ", -$indent), "\n", $content); | |
218 } elseif ($indent > 0) { | |
219 $result .= str_replace("\n", "\n" . str_repeat(" ", $indent), $content); | |
220 } else { | |
221 $result .= $content; | |
222 } | |
223 } | |
224 } else { | |
225 $result .= $token; | |
226 } | |
227 } | |
228 return $result; | |
229 } | |
230 | |
231 /** | |
232 * Precalculate the indentation at every token position. | |
233 * | |
234 * @return int[] Token position to indentation map | |
235 */ | |
236 private function calcIndentMap() { | |
237 $indentMap = []; | |
238 $indent = 0; | |
239 foreach ($this->tokens as $token) { | |
240 $indentMap[] = $indent; | |
241 | |
242 if ($token[0] === \T_WHITESPACE) { | |
243 $content = $token[1]; | |
244 $newlinePos = \strrpos($content, "\n"); | |
245 if (false !== $newlinePos) { | |
246 $indent = \strlen($content) - $newlinePos - 1; | |
247 } | |
248 } | |
249 } | |
250 | |
251 // Add a sentinel for one past end of the file | |
252 $indentMap[] = $indent; | |
253 | |
254 return $indentMap; | |
255 } | |
256 } |