4
4
5
5
namespace Roave \BetterReflection \NodeCompiler ;
6
6
7
+ use PhpParser \ConstExprEvaluator ;
7
8
use PhpParser \Node ;
8
- use ReflectionFunction ;
9
- use Roave \BetterReflection \NodeCompiler \Exception \UnableToCompileNode ;
10
9
use Roave \BetterReflection \Reflection \ReflectionClass ;
11
10
use Roave \BetterReflection \Reflector \Exception \IdentifierNotFound ;
12
11
use Roave \BetterReflection \Util \FileHelper ;
13
- use function array_combine ;
14
- use function array_map ;
15
12
use function constant ;
16
13
use function defined ;
17
14
use function dirname ;
22
19
23
20
class CompileNodeToValue
24
21
{
25
- /** @var callable[]|null indexed by supported expression node class name */
26
- private static $ nodeEvaluators ;
27
-
28
22
/**
29
23
* Compile an expression from a node into a value.
30
24
*
@@ -36,63 +30,31 @@ class CompileNodeToValue
36
30
*/
37
31
public function __invoke (Node $ node , CompilerContext $ context )
38
32
{
39
- if ($ node instanceof Node \Scalar \String_
40
- || $ node instanceof Node \Scalar \DNumber
41
- || $ node instanceof Node \Scalar \LNumber) {
42
- return $ node ->value ;
43
- }
44
-
45
- // common edge case - negative numbers
46
- if ($ node instanceof Node \Expr \UnaryMinus) {
47
- return $ this ($ node ->expr , $ context ) * -1 ;
48
- }
49
-
50
- if ($ node instanceof Node \Expr \Array_) {
51
- return $ this ->compileArray ($ node , $ context );
52
- }
53
-
54
- if ($ node instanceof Node \Expr \ConstFetch) {
55
- return $ this ->compileConstFetch ($ node );
56
- }
57
-
58
- if ($ node instanceof Node \Expr \ClassConstFetch) {
59
- return $ this ->compileClassConstFetch ($ node , $ context );
60
- }
61
-
62
- if ($ node instanceof Node \Expr \BinaryOp) {
63
- return $ this ->compileBinaryOperator ($ node , $ context );
64
- }
65
-
66
- if ($ node instanceof Node \Scalar \MagicConst \Dir) {
67
- return $ this ->compileDirConstant ($ context );
33
+ if ($ node instanceof Node \Stmt \Expression) {
34
+ return $ this ($ node ->expr , $ context );
68
35
}
69
36
70
- if ($ node instanceof Node \Scalar \MagicConst \Class_) {
71
- return $ this ->compileClassConstant ($ context );
72
- }
37
+ $ constExprEvaluator = new ConstExprEvaluator (function (Node \Expr $ node ) use ($ context ) {
38
+ if ($ node instanceof Node \Expr \ConstFetch) {
39
+ return $ this ->compileConstFetch ($ node );
40
+ }
73
41
74
- throw new Exception \UnableToCompileNode ('Unable to compile expression: ' . get_class ($ node ));
75
- }
42
+ if ($ node instanceof Node \Expr \ClassConstFetch) {
43
+ return $ this ->compileClassConstFetch ($ node , $ context );
44
+ }
76
45
77
- /**
78
- * Compile arrays
79
- *
80
- * @return mixed[]
81
- */
82
- private function compileArray (Node \Expr \Array_ $ arrayNode , CompilerContext $ context ) : array
83
- {
84
- $ compiledArray = [];
85
- foreach ($ arrayNode ->items as $ arrayItem ) {
86
- $ compiledValue = $ this ($ arrayItem ->value , $ context );
46
+ if ($ node instanceof Node \Scalar \MagicConst \Dir) {
47
+ return $ this ->compileDirConstant ($ context );
48
+ }
87
49
88
- if ($ arrayItem ->key === null ) {
89
- $ compiledArray [] = $ compiledValue ;
90
- continue ;
50
+ if ($ node instanceof Node \Scalar \MagicConst \Class_) {
51
+ return $ this ->compileClassConstant ($ context );
91
52
}
92
53
93
- $ compiledArray [$ this ($ arrayItem ->key , $ context )] = $ compiledValue ;
94
- }
95
- return $ compiledArray ;
54
+ throw new Exception \UnableToCompileNode ('Unable to compile expression: ' . get_class ($ node ));
55
+ });
56
+
57
+ return $ constExprEvaluator ->evaluateDirectly ($ node );
96
58
}
97
59
98
60
/**
@@ -131,7 +93,7 @@ private function compileConstFetch(Node\Expr\ConstFetch $constNode)
131
93
private function compileClassConstFetch (Node \Expr \ClassConstFetch $ node , CompilerContext $ context )
132
94
{
133
95
/** @var string $nodeName */
134
- $ nodeName = $ node ->name ;
96
+ $ nodeName = $ node ->name -> name ;
135
97
$ className = $ node ->class ->toString ();
136
98
137
99
if ($ nodeName === 'class ' ) {
@@ -158,30 +120,6 @@ private function compileClassConstFetch(Node\Expr\ClassConstFetch $node, Compile
158
120
);
159
121
}
160
122
161
- /**
162
- * Compile a binary operator node
163
- *
164
- *
165
- * @return mixed
166
- *
167
- * @throws UnableToCompileNode
168
- */
169
- private function compileBinaryOperator (Node \Expr \BinaryOp $ node , CompilerContext $ context )
170
- {
171
- $ evaluators = self ::loadEvaluators ();
172
- $ nodeClass = get_class ($ node );
173
-
174
- if (! isset ($ evaluators [$ nodeClass ])) {
175
- throw new Exception \UnableToCompileNode (sprintf (
176
- 'Unable to compile binary operator: %s ' ,
177
- $ nodeClass
178
- ));
179
- }
180
-
181
- // Welcome to method overloading implemented PHP-style. Yay?
182
- return $ evaluators [$ nodeClass ]($ node , $ context , $ this );
183
- }
184
-
185
123
/**
186
124
* Compile a __DIR__ node
187
125
*/
@@ -208,122 +146,4 @@ private function getConstantDeclaringClass(string $constantName, ReflectionClass
208
146
209
147
return $ parentClass ? $ this ->getConstantDeclaringClass ($ constantName , $ parentClass ) : null ;
210
148
}
211
-
212
- /**
213
- * @return callable[] indexed by node class name
214
- */
215
- private static function loadEvaluators () : array
216
- {
217
- if (self ::$ nodeEvaluators ) {
218
- return self ::$ nodeEvaluators ;
219
- }
220
-
221
- $ evaluators = self ::makeEvaluators ();
222
-
223
- return self ::$ nodeEvaluators = array_combine (
224
- array_map (function (callable $ nodeEvaluator ) : string {
225
- /** @noinspection ExceptionsAnnotatingAndHandlingInspection */
226
- /** @noinspection NullPointerExceptionInspection */
227
- return (new ReflectionFunction ($ nodeEvaluator ))->getParameters ()[0 ]->getType ()->getName ();
228
- }, $ evaluators ),
229
- $ evaluators
230
- );
231
- }
232
-
233
- /**
234
- * @return callable[]
235
- */
236
- private static function makeEvaluators () : array
237
- {
238
- return [
239
- function (Node \Expr \BinaryOp \Plus $ node , CompilerContext $ context , self $ next ) {
240
- return $ next ($ node ->left , $ context ) + $ next ($ node ->right , $ context );
241
- },
242
- function (Node \Expr \BinaryOp \Mul $ node , CompilerContext $ context , self $ next ) {
243
- return $ next ($ node ->left , $ context ) * $ next ($ node ->right , $ context );
244
- },
245
- function (Node \Expr \BinaryOp \Minus $ node , CompilerContext $ context , self $ next ) {
246
- return $ next ($ node ->left , $ context ) - $ next ($ node ->right , $ context );
247
- },
248
- function (Node \Expr \BinaryOp \Div $ node , CompilerContext $ context , self $ next ) {
249
- return $ next ($ node ->left , $ context ) / $ next ($ node ->right , $ context );
250
- },
251
- function (Node \Expr \BinaryOp \Concat $ node , CompilerContext $ context , self $ next ) {
252
- return $ next ($ node ->left , $ context ) . $ next ($ node ->right , $ context );
253
- },
254
- function (Node \Expr \BinaryOp \BooleanAnd $ node , CompilerContext $ context , self $ next ) {
255
- return $ next ($ node ->left , $ context ) && $ next ($ node ->right , $ context );
256
- },
257
- function (Node \Expr \BinaryOp \BooleanOr $ node , CompilerContext $ context , self $ next ) {
258
- return $ next ($ node ->left , $ context ) || $ next ($ node ->right , $ context );
259
- },
260
- function (Node \Expr \BinaryOp \BitwiseAnd $ node , CompilerContext $ context , self $ next ) {
261
- return $ next ($ node ->left , $ context ) & $ next ($ node ->right , $ context );
262
- },
263
- function (Node \Expr \BinaryOp \BitwiseOr $ node , CompilerContext $ context , self $ next ) {
264
- return $ next ($ node ->left , $ context ) | $ next ($ node ->right , $ context );
265
- },
266
- function (Node \Expr \BinaryOp \BitwiseXor $ node , CompilerContext $ context , self $ next ) {
267
- return $ next ($ node ->left , $ context ) ^ $ next ($ node ->right , $ context );
268
- },
269
- function (Node \Expr \BinaryOp \Equal $ node , CompilerContext $ context , self $ next ) {
270
- /** @noinspection TypeUnsafeComparisonInspection */
271
- // phpcs:disable SlevomatCodingStandard.ControlStructures.DisallowEqualOperators
272
- return $ next ($ node ->left , $ context ) == $ next ($ node ->right , $ context );
273
- // phpcs:enable
274
- },
275
- function (Node \Expr \BinaryOp \Greater $ node , CompilerContext $ context , self $ next ) {
276
- return $ next ($ node ->left , $ context ) > $ next ($ node ->right , $ context );
277
- },
278
- function (Node \Expr \BinaryOp \GreaterOrEqual $ node , CompilerContext $ context , self $ next ) {
279
- return $ next ($ node ->left , $ context ) >= $ next ($ node ->right , $ context );
280
- },
281
- function (Node \Expr \BinaryOp \Identical $ node , CompilerContext $ context , self $ next ) {
282
- return $ next ($ node ->left , $ context ) === $ next ($ node ->right , $ context );
283
- },
284
- function (Node \Expr \BinaryOp \LogicalAnd $ node , CompilerContext $ context , self $ next ) {
285
- // phpcs:disable Squiz.Operators.ValidLogicalOperators.NotAllowed
286
- return $ next ($ node ->left , $ context ) and $ next ($ node ->right , $ context );
287
- // phpcs:enable
288
- },
289
- function (Node \Expr \BinaryOp \LogicalOr $ node , CompilerContext $ context , self $ next ) {
290
- // phpcs:disable Squiz.Operators.ValidLogicalOperators.NotAllowed
291
- return $ next ($ node ->left , $ context ) or $ next ($ node ->right , $ context );
292
- // phpcs:enable
293
- },
294
- function (Node \Expr \BinaryOp \LogicalXor $ node , CompilerContext $ context , self $ next ) {
295
- return $ next ($ node ->left , $ context ) xor $ next ($ node ->right , $ context );
296
- },
297
- function (Node \Expr \BinaryOp \Mod $ node , CompilerContext $ context , self $ next ) {
298
- return $ next ($ node ->left , $ context ) % $ next ($ node ->right , $ context );
299
- },
300
- function (Node \Expr \BinaryOp \NotEqual $ node , CompilerContext $ context , self $ next ) {
301
- /** @noinspection TypeUnsafeComparisonInspection */
302
- // phpcs:disable SlevomatCodingStandard.ControlStructures.DisallowEqualOperators
303
- return $ next ($ node ->left , $ context ) != $ next ($ node ->right , $ context );
304
- // phpcs:enable
305
- },
306
- function (Node \Expr \BinaryOp \NotIdentical $ node , CompilerContext $ context , self $ next ) {
307
- return $ next ($ node ->left , $ context ) !== $ next ($ node ->right , $ context );
308
- },
309
- function (Node \Expr \BinaryOp \Pow $ node , CompilerContext $ context , self $ next ) {
310
- return $ next ($ node ->left , $ context ) ** $ next ($ node ->right , $ context );
311
- },
312
- function (Node \Expr \BinaryOp \ShiftLeft $ node , CompilerContext $ context , self $ next ) {
313
- return $ next ($ node ->left , $ context ) << $ next ($ node ->right , $ context );
314
- },
315
- function (Node \Expr \BinaryOp \ShiftRight $ node , CompilerContext $ context , self $ next ) {
316
- return $ next ($ node ->left , $ context ) >> $ next ($ node ->right , $ context );
317
- },
318
- function (Node \Expr \BinaryOp \Smaller $ node , CompilerContext $ context , self $ next ) {
319
- return $ next ($ node ->left , $ context ) < $ next ($ node ->right , $ context );
320
- },
321
- function (Node \Expr \BinaryOp \SmallerOrEqual $ node , CompilerContext $ context , self $ next ) {
322
- return $ next ($ node ->left , $ context ) <= $ next ($ node ->right , $ context );
323
- },
324
- function (Node \Expr \BinaryOp \Spaceship $ node , CompilerContext $ context , self $ next ) {
325
- return $ next ($ node ->left , $ context ) <=> $ next ($ node ->right , $ context );
326
- },
327
- ];
328
- }
329
149
}
0 commit comments