| 148 |
lars |
1 |
<?php declare(strict_types=1);
|
|
|
2 |
|
|
|
3 |
namespace PhpParser;
|
|
|
4 |
|
|
|
5 |
use PhpParser\Node\ComplexType;
|
|
|
6 |
use PhpParser\Node\Expr;
|
|
|
7 |
use PhpParser\Node\Identifier;
|
|
|
8 |
use PhpParser\Node\Name;
|
|
|
9 |
use PhpParser\Node\NullableType;
|
|
|
10 |
use PhpParser\Node\Scalar;
|
|
|
11 |
use PhpParser\Node\Stmt;
|
|
|
12 |
|
|
|
13 |
/**
|
|
|
14 |
* This class defines helpers used in the implementation of builders. Don't use it directly.
|
|
|
15 |
*
|
|
|
16 |
* @internal
|
|
|
17 |
*/
|
|
|
18 |
final class BuilderHelpers
|
|
|
19 |
{
|
|
|
20 |
/**
|
|
|
21 |
* Normalizes a node: Converts builder objects to nodes.
|
|
|
22 |
*
|
|
|
23 |
* @param Node|Builder $node The node to normalize
|
|
|
24 |
*
|
|
|
25 |
* @return Node The normalized node
|
|
|
26 |
*/
|
|
|
27 |
public static function normalizeNode($node) : Node {
|
|
|
28 |
if ($node instanceof Builder) {
|
|
|
29 |
return $node->getNode();
|
|
|
30 |
}
|
|
|
31 |
|
|
|
32 |
if ($node instanceof Node) {
|
|
|
33 |
return $node;
|
|
|
34 |
}
|
|
|
35 |
|
|
|
36 |
throw new \LogicException('Expected node or builder object');
|
|
|
37 |
}
|
|
|
38 |
|
|
|
39 |
/**
|
|
|
40 |
* Normalizes a node to a statement.
|
|
|
41 |
*
|
|
|
42 |
* Expressions are wrapped in a Stmt\Expression node.
|
|
|
43 |
*
|
|
|
44 |
* @param Node|Builder $node The node to normalize
|
|
|
45 |
*
|
|
|
46 |
* @return Stmt The normalized statement node
|
|
|
47 |
*/
|
|
|
48 |
public static function normalizeStmt($node) : Stmt {
|
|
|
49 |
$node = self::normalizeNode($node);
|
|
|
50 |
if ($node instanceof Stmt) {
|
|
|
51 |
return $node;
|
|
|
52 |
}
|
|
|
53 |
|
|
|
54 |
if ($node instanceof Expr) {
|
|
|
55 |
return new Stmt\Expression($node);
|
|
|
56 |
}
|
|
|
57 |
|
|
|
58 |
throw new \LogicException('Expected statement or expression node');
|
|
|
59 |
}
|
|
|
60 |
|
|
|
61 |
/**
|
|
|
62 |
* Normalizes strings to Identifier.
|
|
|
63 |
*
|
|
|
64 |
* @param string|Identifier $name The identifier to normalize
|
|
|
65 |
*
|
|
|
66 |
* @return Identifier The normalized identifier
|
|
|
67 |
*/
|
|
|
68 |
public static function normalizeIdentifier($name) : Identifier {
|
|
|
69 |
if ($name instanceof Identifier) {
|
|
|
70 |
return $name;
|
|
|
71 |
}
|
|
|
72 |
|
|
|
73 |
if (\is_string($name)) {
|
|
|
74 |
return new Identifier($name);
|
|
|
75 |
}
|
|
|
76 |
|
|
|
77 |
throw new \LogicException('Expected string or instance of Node\Identifier');
|
|
|
78 |
}
|
|
|
79 |
|
|
|
80 |
/**
|
|
|
81 |
* Normalizes strings to Identifier, also allowing expressions.
|
|
|
82 |
*
|
|
|
83 |
* @param string|Identifier|Expr $name The identifier to normalize
|
|
|
84 |
*
|
|
|
85 |
* @return Identifier|Expr The normalized identifier or expression
|
|
|
86 |
*/
|
|
|
87 |
public static function normalizeIdentifierOrExpr($name) {
|
|
|
88 |
if ($name instanceof Identifier || $name instanceof Expr) {
|
|
|
89 |
return $name;
|
|
|
90 |
}
|
|
|
91 |
|
|
|
92 |
if (\is_string($name)) {
|
|
|
93 |
return new Identifier($name);
|
|
|
94 |
}
|
|
|
95 |
|
|
|
96 |
throw new \LogicException('Expected string or instance of Node\Identifier or Node\Expr');
|
|
|
97 |
}
|
|
|
98 |
|
|
|
99 |
/**
|
|
|
100 |
* Normalizes a name: Converts string names to Name nodes.
|
|
|
101 |
*
|
|
|
102 |
* @param Name|string $name The name to normalize
|
|
|
103 |
*
|
|
|
104 |
* @return Name The normalized name
|
|
|
105 |
*/
|
|
|
106 |
public static function normalizeName($name) : Name {
|
|
|
107 |
if ($name instanceof Name) {
|
|
|
108 |
return $name;
|
|
|
109 |
}
|
|
|
110 |
|
|
|
111 |
if (is_string($name)) {
|
|
|
112 |
if (!$name) {
|
|
|
113 |
throw new \LogicException('Name cannot be empty');
|
|
|
114 |
}
|
|
|
115 |
|
|
|
116 |
if ($name[0] === '\\') {
|
|
|
117 |
return new Name\FullyQualified(substr($name, 1));
|
|
|
118 |
}
|
|
|
119 |
|
|
|
120 |
if (0 === strpos($name, 'namespace\\')) {
|
|
|
121 |
return new Name\Relative(substr($name, strlen('namespace\\')));
|
|
|
122 |
}
|
|
|
123 |
|
|
|
124 |
return new Name($name);
|
|
|
125 |
}
|
|
|
126 |
|
|
|
127 |
throw new \LogicException('Name must be a string or an instance of Node\Name');
|
|
|
128 |
}
|
|
|
129 |
|
|
|
130 |
/**
|
|
|
131 |
* Normalizes a name: Converts string names to Name nodes, while also allowing expressions.
|
|
|
132 |
*
|
|
|
133 |
* @param Expr|Name|string $name The name to normalize
|
|
|
134 |
*
|
|
|
135 |
* @return Name|Expr The normalized name or expression
|
|
|
136 |
*/
|
|
|
137 |
public static function normalizeNameOrExpr($name) {
|
|
|
138 |
if ($name instanceof Expr) {
|
|
|
139 |
return $name;
|
|
|
140 |
}
|
|
|
141 |
|
|
|
142 |
if (!is_string($name) && !($name instanceof Name)) {
|
|
|
143 |
throw new \LogicException(
|
|
|
144 |
'Name must be a string or an instance of Node\Name or Node\Expr'
|
|
|
145 |
);
|
|
|
146 |
}
|
|
|
147 |
|
|
|
148 |
return self::normalizeName($name);
|
|
|
149 |
}
|
|
|
150 |
|
|
|
151 |
/**
|
|
|
152 |
* Normalizes a type: Converts plain-text type names into proper AST representation.
|
|
|
153 |
*
|
|
|
154 |
* In particular, builtin types become Identifiers, custom types become Names and nullables
|
|
|
155 |
* are wrapped in NullableType nodes.
|
|
|
156 |
*
|
|
|
157 |
* @param string|Name|Identifier|ComplexType $type The type to normalize
|
|
|
158 |
*
|
|
|
159 |
* @return Name|Identifier|ComplexType The normalized type
|
|
|
160 |
*/
|
|
|
161 |
public static function normalizeType($type) {
|
|
|
162 |
if (!is_string($type)) {
|
|
|
163 |
if (
|
|
|
164 |
!$type instanceof Name && !$type instanceof Identifier &&
|
|
|
165 |
!$type instanceof ComplexType
|
|
|
166 |
) {
|
|
|
167 |
throw new \LogicException(
|
|
|
168 |
'Type must be a string, or an instance of Name, Identifier or ComplexType'
|
|
|
169 |
);
|
|
|
170 |
}
|
|
|
171 |
return $type;
|
|
|
172 |
}
|
|
|
173 |
|
|
|
174 |
$nullable = false;
|
|
|
175 |
if (strlen($type) > 0 && $type[0] === '?') {
|
|
|
176 |
$nullable = true;
|
|
|
177 |
$type = substr($type, 1);
|
|
|
178 |
}
|
|
|
179 |
|
|
|
180 |
$builtinTypes = [
|
|
|
181 |
'array',
|
|
|
182 |
'callable',
|
|
|
183 |
'bool',
|
|
|
184 |
'int',
|
|
|
185 |
'float',
|
|
|
186 |
'string',
|
|
|
187 |
'iterable',
|
|
|
188 |
'void',
|
|
|
189 |
'object',
|
|
|
190 |
'null',
|
|
|
191 |
'false',
|
|
|
192 |
'mixed',
|
|
|
193 |
'never',
|
|
|
194 |
'true',
|
|
|
195 |
];
|
|
|
196 |
|
|
|
197 |
$lowerType = strtolower($type);
|
|
|
198 |
if (in_array($lowerType, $builtinTypes)) {
|
|
|
199 |
$type = new Identifier($lowerType);
|
|
|
200 |
} else {
|
|
|
201 |
$type = self::normalizeName($type);
|
|
|
202 |
}
|
|
|
203 |
|
|
|
204 |
$notNullableTypes = [
|
|
|
205 |
'void', 'mixed', 'never',
|
|
|
206 |
];
|
|
|
207 |
if ($nullable && in_array((string) $type, $notNullableTypes)) {
|
|
|
208 |
throw new \LogicException(sprintf('%s type cannot be nullable', $type));
|
|
|
209 |
}
|
|
|
210 |
|
|
|
211 |
return $nullable ? new NullableType($type) : $type;
|
|
|
212 |
}
|
|
|
213 |
|
|
|
214 |
/**
|
|
|
215 |
* Normalizes a value: Converts nulls, booleans, integers,
|
|
|
216 |
* floats, strings and arrays into their respective nodes
|
|
|
217 |
*
|
|
|
218 |
* @param Node\Expr|bool|null|int|float|string|array $value The value to normalize
|
|
|
219 |
*
|
|
|
220 |
* @return Expr The normalized value
|
|
|
221 |
*/
|
|
|
222 |
public static function normalizeValue($value) : Expr {
|
|
|
223 |
if ($value instanceof Node\Expr) {
|
|
|
224 |
return $value;
|
|
|
225 |
}
|
|
|
226 |
|
|
|
227 |
if (is_null($value)) {
|
|
|
228 |
return new Expr\ConstFetch(
|
|
|
229 |
new Name('null')
|
|
|
230 |
);
|
|
|
231 |
}
|
|
|
232 |
|
|
|
233 |
if (is_bool($value)) {
|
|
|
234 |
return new Expr\ConstFetch(
|
|
|
235 |
new Name($value ? 'true' : 'false')
|
|
|
236 |
);
|
|
|
237 |
}
|
|
|
238 |
|
|
|
239 |
if (is_int($value)) {
|
|
|
240 |
return new Scalar\LNumber($value);
|
|
|
241 |
}
|
|
|
242 |
|
|
|
243 |
if (is_float($value)) {
|
|
|
244 |
return new Scalar\DNumber($value);
|
|
|
245 |
}
|
|
|
246 |
|
|
|
247 |
if (is_string($value)) {
|
|
|
248 |
return new Scalar\String_($value);
|
|
|
249 |
}
|
|
|
250 |
|
|
|
251 |
if (is_array($value)) {
|
|
|
252 |
$items = [];
|
|
|
253 |
$lastKey = -1;
|
|
|
254 |
foreach ($value as $itemKey => $itemValue) {
|
|
|
255 |
// for consecutive, numeric keys don't generate keys
|
|
|
256 |
if (null !== $lastKey && ++$lastKey === $itemKey) {
|
|
|
257 |
$items[] = new Expr\ArrayItem(
|
|
|
258 |
self::normalizeValue($itemValue)
|
|
|
259 |
);
|
|
|
260 |
} else {
|
|
|
261 |
$lastKey = null;
|
|
|
262 |
$items[] = new Expr\ArrayItem(
|
|
|
263 |
self::normalizeValue($itemValue),
|
|
|
264 |
self::normalizeValue($itemKey)
|
|
|
265 |
);
|
|
|
266 |
}
|
|
|
267 |
}
|
|
|
268 |
|
|
|
269 |
return new Expr\Array_($items);
|
|
|
270 |
}
|
|
|
271 |
|
|
|
272 |
throw new \LogicException('Invalid value');
|
|
|
273 |
}
|
|
|
274 |
|
|
|
275 |
/**
|
|
|
276 |
* Normalizes a doc comment: Converts plain strings to PhpParser\Comment\Doc.
|
|
|
277 |
*
|
|
|
278 |
* @param Comment\Doc|string $docComment The doc comment to normalize
|
|
|
279 |
*
|
|
|
280 |
* @return Comment\Doc The normalized doc comment
|
|
|
281 |
*/
|
|
|
282 |
public static function normalizeDocComment($docComment) : Comment\Doc {
|
|
|
283 |
if ($docComment instanceof Comment\Doc) {
|
|
|
284 |
return $docComment;
|
|
|
285 |
}
|
|
|
286 |
|
|
|
287 |
if (is_string($docComment)) {
|
|
|
288 |
return new Comment\Doc($docComment);
|
|
|
289 |
}
|
|
|
290 |
|
|
|
291 |
throw new \LogicException('Doc comment must be a string or an instance of PhpParser\Comment\Doc');
|
|
|
292 |
}
|
|
|
293 |
|
|
|
294 |
/**
|
|
|
295 |
* Normalizes a attribute: Converts attribute to the Attribute Group if needed.
|
|
|
296 |
*
|
|
|
297 |
* @param Node\Attribute|Node\AttributeGroup $attribute
|
|
|
298 |
*
|
|
|
299 |
* @return Node\AttributeGroup The Attribute Group
|
|
|
300 |
*/
|
|
|
301 |
public static function normalizeAttribute($attribute) : Node\AttributeGroup
|
|
|
302 |
{
|
|
|
303 |
if ($attribute instanceof Node\AttributeGroup) {
|
|
|
304 |
return $attribute;
|
|
|
305 |
}
|
|
|
306 |
|
|
|
307 |
if (!($attribute instanceof Node\Attribute)) {
|
|
|
308 |
throw new \LogicException('Attribute must be an instance of PhpParser\Node\Attribute or PhpParser\Node\AttributeGroup');
|
|
|
309 |
}
|
|
|
310 |
|
|
|
311 |
return new Node\AttributeGroup([$attribute]);
|
|
|
312 |
}
|
|
|
313 |
|
|
|
314 |
/**
|
|
|
315 |
* Adds a modifier and returns new modifier bitmask.
|
|
|
316 |
*
|
|
|
317 |
* @param int $modifiers Existing modifiers
|
|
|
318 |
* @param int $modifier Modifier to set
|
|
|
319 |
*
|
|
|
320 |
* @return int New modifiers
|
|
|
321 |
*/
|
|
|
322 |
public static function addModifier(int $modifiers, int $modifier) : int {
|
|
|
323 |
Stmt\Class_::verifyModifier($modifiers, $modifier);
|
|
|
324 |
return $modifiers | $modifier;
|
|
|
325 |
}
|
|
|
326 |
|
|
|
327 |
/**
|
|
|
328 |
* Adds a modifier and returns new modifier bitmask.
|
|
|
329 |
* @return int New modifiers
|
|
|
330 |
*/
|
|
|
331 |
public static function addClassModifier(int $existingModifiers, int $modifierToSet) : int {
|
|
|
332 |
Stmt\Class_::verifyClassModifier($existingModifiers, $modifierToSet);
|
|
|
333 |
return $existingModifiers | $modifierToSet;
|
|
|
334 |
}
|
|
|
335 |
}
|