1
1
<?php namespace lang \ast \emit ;
2
2
3
- use lang \ast \nodes \{CallableExpression , CallableNewExpression , Variable };
3
+ use lang \ast \nodes \{CallableExpression , CallableNewExpression , Literal , Variable };
4
4
5
5
/**
6
6
* Emulates pipelines / the pipe operator, including a null-safe version.
7
7
*
8
+ * ```php
9
+ * // Enclose expressions as follows:
10
+ * $in |> $expr;
11
+ * ($expr)($in);
12
+ *
13
+ * // Optimize for string literals:
14
+ * $in |> 'strlen';
15
+ * strlen($in);
16
+ *
17
+ * // Optimize for first-class callables:
18
+ * $in |> strlen(...);
19
+ * strlen($in);
20
+ * ```
21
+ *
8
22
* @see https://wiki.php.net/rfc/pipe-operator-v3
9
23
* @see https://externals.io/message/107661#107670
24
+ * @test lang.ast.unittest.emit.EmulatePipelinesTest
10
25
* @test lang.ast.unittest.emit.PipelinesTest
11
26
*/
12
27
trait EmulatePipelines {
13
28
14
29
protected function emitPipeTarget ($ result , $ target , $ arg ) {
15
30
if ($ target instanceof CallableNewExpression) {
16
- $ target ->type ->arguments = [new Variable ( substr ( $ arg, 1 )) ];
31
+ $ target ->type ->arguments = [$ arg ];
17
32
$ this ->emitOne ($ result , $ target ->type );
18
33
$ target ->type ->arguments = null ;
19
34
} else if ($ target instanceof CallableExpression) {
20
35
$ this ->emitOne ($ result , $ target ->expression );
21
- $ result ->out ->write ('( ' .$ arg .') ' );
36
+ $ result ->out ->write ('( ' );
37
+ $ this ->emitOne ($ result , $ arg );
38
+ $ result ->out ->write (') ' );
39
+ } else if ($ target instanceof Literal) {
40
+ $ result ->out ->write (trim ($ target ->expression , '" \'' ));
41
+ $ result ->out ->write ('( ' );
42
+ $ this ->emitOne ($ result , $ arg );
43
+ $ result ->out ->write (') ' );
22
44
} else {
23
45
$ result ->out ->write ('( ' );
24
46
$ this ->emitOne ($ result , $ target );
25
- $ result ->out ->write (')( ' .$ arg .') ' );
47
+ $ result ->out ->write (')( ' );
48
+ $ this ->emitOne ($ result , $ arg );
49
+ $ result ->out ->write (') ' );
26
50
}
27
51
}
28
52
29
53
protected function emitPipe ($ result , $ pipe ) {
30
54
31
- // $expr |> strtoupper(...) => [$arg= $expr, strtoupper($arg)][1]
32
- $ t = $ result ->temp ();
33
- $ result ->out ->write ('[ ' .$ t .'= ' );
34
- $ this ->emitOne ($ result , $ pipe ->expression );
35
- $ result ->out ->write (', ' );
36
- $ this ->emitPipeTarget ($ result , $ pipe ->target , $ t );
37
- $ result ->out ->write ('][1] ' );
55
+ // <const> |> strtoupper(...) => strtoupper(<const>)
56
+ // <expr> |> strtoupper(...) => [$arg= <expr>, strtoupper($arg)][1]
57
+ if ($ this ->isConstant ($ result , $ pipe ->expression )) {
58
+ $ this ->emitPipeTarget ($ result , $ pipe ->target , $ pipe ->expression );
59
+ } else {
60
+ $ t = $ result ->temp ();
61
+ $ result ->out ->write ('[ ' .$ t .'= ' );
62
+ $ this ->emitOne ($ result , $ pipe ->expression );
63
+ $ result ->out ->write (', ' );
64
+ $ this ->emitPipeTarget ($ result , $ pipe ->target , new Variable (substr ($ t , 1 )));
65
+ $ result ->out ->write ('][1] ' );
66
+ }
38
67
}
39
68
40
69
protected function emitNullsafePipe ($ result , $ pipe ) {
41
70
42
- // $ expr ?|> strtoupper(...) => null === ($arg= $ expr) ? null : strtoupper($arg)
71
+ // < expr> ?|> strtoupper(...) => null === ($arg= < expr> ) ? null : strtoupper($arg)
43
72
$ t = $ result ->temp ();
44
73
$ result ->out ->write ('null===( ' .$ t .'= ' );
45
74
$ this ->emitOne ($ result , $ pipe ->expression );
46
75
$ result ->out ->write (')?null: ' );
47
- $ this ->emitPipeTarget ($ result , $ pipe ->target , $ t );
76
+ $ this ->emitPipeTarget ($ result , $ pipe ->target , new Variable ( substr ( $ t , 1 )) );
48
77
}
49
78
}
0 commit comments