Skip to content

Commit 651cd92

Browse files
authored
Merge pull request #181 from xp-framework/feature/pipelines
Add support for pipelines with `|>` and `?|>`
2 parents 9d21030 + d309fea commit 651cd92

11 files changed

+474
-5
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"require" : {
99
"xp-framework/core": "^12.0 | ^11.6 | ^10.16",
1010
"xp-framework/reflection": "^3.2 | ^2.15",
11-
"xp-framework/ast": "^11.5",
11+
"xp-framework/ast": "^11.6",
1212
"php" : ">=7.4.0"
1313
},
1414
"require-dev" : {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php namespace lang\ast\emit;
2+
3+
use lang\ast\nodes\{CallableExpression, CallableNewExpression, Variable};
4+
5+
/**
6+
* Emulates pipelines / the pipe operator, including a null-safe version.
7+
*
8+
* @see https://wiki.php.net/rfc/pipe-operator-v3
9+
* @see https://externals.io/message/107661#107670
10+
* @test lang.ast.unittest.emit.PipelinesTest
11+
*/
12+
trait EmulatePipelines {
13+
14+
protected function emitPipeTarget($result, $target, $arg) {
15+
if ($target instanceof CallableNewExpression) {
16+
$target->type->arguments= [new Variable(substr($arg, 1))];
17+
$this->emitOne($result, $target->type);
18+
$target->type->arguments= null;
19+
} else if ($target instanceof CallableExpression) {
20+
$this->emitOne($result, $target->expression);
21+
$result->out->write('('.$arg.')');
22+
} else {
23+
$result->out->write('(');
24+
$this->emitOne($result, $target);
25+
$result->out->write(')('.$arg.')');
26+
}
27+
}
28+
29+
protected function emitPipe($result, $pipe) {
30+
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]');
38+
}
39+
40+
protected function emitNullsafePipe($result, $pipe) {
41+
42+
// $expr ?|> strtoupper(...) => null === ($arg= $expr) ? null : strtoupper($arg)
43+
$t= $result->temp();
44+
$result->out->write('null===('.$t.'=');
45+
$this->emitOne($result, $pipe->expression);
46+
$result->out->write(')?null:');
47+
$this->emitPipeTarget($result, $pipe->target, $t);
48+
}
49+
}

src/main/php/lang/ast/emit/PHP.class.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,6 +1156,22 @@ protected function emitNullsafeInstance($result, $instance) {
11561156
$this->emitOne($result, $instance->member);
11571157
}
11581158

1159+
protected function emitPipe($result, $pipe) {
1160+
$this->emitOne($result, $pipe->expression);
1161+
$result->out->write('|>');
1162+
$this->emitOne($result, $pipe->target);
1163+
}
1164+
1165+
protected function emitNullsafePipe($result, $pipe) {
1166+
1167+
// $expr ?|> strtoupper(...) => null === ($t= $expr) ? null : $t |> strtoupper(...)
1168+
$t= $result->temp();
1169+
$result->out->write('null===('.$t.'=');
1170+
$this->emitOne($result, $pipe->expression);
1171+
$result->out->write(')?null:'.$t.'|>');
1172+
$this->emitOne($result, $pipe->target);
1173+
}
1174+
11591175
protected function emitUnpack($result, $unpack) {
11601176
$result->out->write('...');
11611177
$this->emitOne($result, $unpack->expression);

src/main/php/lang/ast/emit/PHP74.class.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class PHP74 extends PHP {
1414
AttributesAsComments,
1515
CallablesAsClosures,
1616
ChainScopeOperators,
17+
EmulatePipelines,
1718
MatchAsTernaries,
1819
NonCapturingCatchVariables,
1920
NullsafeAsTernaries,

src/main/php/lang/ast/emit/PHP80.class.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class PHP80 extends PHP {
2121
use
2222
ArrayUnpackUsingMerge,
2323
CallablesAsClosures,
24+
EmulatePipelines,
2425
OmitConstantTypes,
2526
ReadonlyClasses,
2627
RewriteBlockLambdaExpressions,

src/main/php/lang/ast/emit/PHP81.class.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121
class PHP81 extends PHP {
2222
use
23+
EmulatePipelines,
2324
RewriteBlockLambdaExpressions,
2425
RewriteDynamicClassConstants,
2526
RewriteStaticVariableInitializations,

src/main/php/lang/ast/emit/PHP82.class.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121
class PHP82 extends PHP {
2222
use
23+
EmulatePipelines,
2324
RewriteBlockLambdaExpressions,
2425
RewriteDynamicClassConstants,
2526
RewriteStaticVariableInitializations,

src/main/php/lang/ast/emit/PHP83.class.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
/**
1616
* PHP 8.3 syntax
1717
*
18+
* @test lang.ast.unittest.emit.PHP83Test
1819
* @see https://wiki.php.net/rfc#php_83
1920
*/
2021
class PHP83 extends PHP {
21-
use RewriteBlockLambdaExpressions, RewriteProperties;
22+
use EmulatePipelines, RewriteBlockLambdaExpressions, RewriteProperties;
2223

2324
public $targetVersion= 80300;
2425

src/main/php/lang/ast/emit/PHP84.class.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
/**
1616
* PHP 8.4 syntax
1717
*
18+
* @test lang.ast.unittest.emit.PHP84Test
1819
* @see https://wiki.php.net/rfc#php_84
1920
*/
2021
class PHP84 extends PHP {
21-
use RewriteBlockLambdaExpressions;
22+
use EmulatePipelines, RewriteBlockLambdaExpressions;
2223

2324
public $targetVersion= 80400;
2425

0 commit comments

Comments
 (0)