Skip to content

Commit 10eaf45

Browse files
committed
Implement partial function application
See https://wiki.php.net/rfc/partial_function_application_v2
1 parent 7ecf3a3 commit 10eaf45

12 files changed

+136
-27
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.7",
11+
"xp-framework/ast": "dev-feature/pfa as 11.8.0",
1212
"php" : ">=7.4.0"
1313
},
1414
"require-dev" : {

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
11
<?php namespace lang\ast\emit;
22

33
use lang\ast\Node;
4-
use lang\ast\nodes\{Expression, InstanceExpression, ScopeExpression, Literal};
4+
use lang\ast\nodes\{Expression, InstanceExpression, ScopeExpression, Literal, Placeholder};
55

66
/**
77
* Rewrites callable expressions to `Callable::fromClosure()`
88
*
99
* @see https://www.php.net/manual/de/closure.fromcallable.php
10+
* @see https://wiki.php.net/rfc/clone_with_v2
1011
* @see https://wiki.php.net/rfc/first_class_callable_syntax
12+
* @see https://wiki.php.net/rfc/partial_function_application_v2
1113
*/
1214
trait CallablesAsClosures {
15+
use RewritePartialFunctionApplications { emitCallable as emitPartial; }
1316

1417
private function emitQuoted($result, $node) {
1518
if ($node instanceof Literal) {
1619

17-
// Rewrite f() => "f"
20+
// Rewrite f(...) => "f"
1821
$result->out->write('"'.trim($node, '"\'').'"');
1922
} else if ($node instanceof InstanceExpression) {
2023

21-
// Rewrite $this->f => [$this, "f"]
24+
// Rewrite $this->f(...) => [$this, "f"]
2225
$result->out->write('[');
2326
$this->emitOne($result, $node->expression);
2427
$result->out->write(',');
2528
$this->emitQuoted($result, $node->member);
2629
$result->out->write(']');
2730
} else if ($node instanceof ScopeExpression) {
2831

29-
// Rewrite T::f => [T::class, "f"]
32+
// Rewrite T::f(...) => [T::class, "f"]
3033
$result->out->write('[');
3134
if ($node->type instanceof Node) {
3235
$this->emitOne($result, $node->type);
@@ -38,7 +41,7 @@ private function emitQuoted($result, $node) {
3841
$result->out->write(']');
3942
} else if ($node instanceof Expression) {
4043

41-
// Rewrite T::{<f>} => [T::class, <f>]
44+
// Rewrite T::{<f>}(...) => [T::class, <f>]
4245
$this->emitOne($result, $node->inline);
4346
} else {
4447

@@ -50,6 +53,8 @@ private function emitQuoted($result, $node) {
5053
protected function emitCallable($result, $callable) {
5154
if ($callable->expression instanceof Literal && 'clone' === $callable->expression->expression) {
5255
$result->out->write('fn($o) => clone $o');
56+
} else if ([Placeholder::$VARIADIC] !== $callable->arguments) {
57+
$this->emitPartial($result, $callable);
5358
} else {
5459
$result->out->write('\Closure::fromCallable(');
5560
$this->emitQuoted($result, $callable->expression);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
InstanceExpression,
1313
Literal,
1414
NewExpression,
15+
Placeholder,
1516
Property,
1617
ScopeExpression,
1718
UnpackExpression,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class PHP81 extends PHP {
2222
use
2323
EmulatePipelines,
2424
RewriteBlockLambdaExpressions,
25-
RewriteCallableClone,
25+
RewriteCallables,
2626
RewriteCloneWith,
2727
RewriteDynamicClassConstants,
2828
RewriteStaticVariableInitializations,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class PHP82 extends PHP {
2222
use
2323
EmulatePipelines,
2424
RewriteBlockLambdaExpressions,
25-
RewriteCallableClone,
25+
RewriteCallables,
2626
RewriteCloneWith,
2727
RewriteDynamicClassConstants,
2828
RewriteStaticVariableInitializations,

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@
1919
* @see https://wiki.php.net/rfc#php_83
2020
*/
2121
class PHP83 extends PHP {
22-
use EmulatePipelines, RewriteCallableClone, RewriteCloneWith, RewriteBlockLambdaExpressions, RewriteProperties;
22+
use
23+
EmulatePipelines,
24+
RewriteCallables,
25+
RewriteCloneWith,
26+
RewriteBlockLambdaExpressions,
27+
RewriteProperties
28+
;
2329

2430
public $targetVersion= 80300;
2531

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@
1919
* @see https://wiki.php.net/rfc#php_84
2020
*/
2121
class PHP84 extends PHP {
22-
use EmulatePipelines, RewriteCallableClone, RewriteCloneWith, RewriteBlockLambdaExpressions;
22+
use
23+
EmulatePipelines,
24+
RewriteCallables,
25+
RewriteCloneWith,
26+
RewriteBlockLambdaExpressions
27+
;
2328

2429
public $targetVersion= 80400;
2530

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
* @see https://wiki.php.net/rfc#php_85
2020
*/
2121
class PHP85 extends PHP {
22-
use RewriteBlockLambdaExpressions, RewriteCallableClone, RewriteCloneWith; // TODO: Remove once PR is merged!
22+
use RewriteBlockLambdaExpressions, RewriteCallables, RewriteCloneWith; // TODO: Remove once PR is merged!
2323

2424
public $targetVersion= 80500;
2525

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

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php namespace lang\ast\emit;
2+
3+
use lang\ast\nodes\Literal;
4+
5+
/**
6+
* Rewrites `clone(...)` and partial function applications
7+
*
8+
* @see https://wiki.php.net/rfc/clone_with_v2
9+
* @see https://wiki.php.net/rfc/partial_function_application_v2
10+
*/
11+
trait RewriteCallables {
12+
use RewritePartialFunctionApplications { emitCallable as emitPartial; }
13+
14+
protected function emitCallable($result, $callable) {
15+
if ($callable->expression instanceof Literal && 'clone' === $callable->expression->expression) {
16+
$result->out->write('fn($o) => clone $o');
17+
} else {
18+
$this->emitPartial($result, $callable);
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)