Skip to content

Commit e5e7fe1

Browse files
committed
added support for Partial Function Application WIP
1 parent cac05ea commit e5e7fe1

File tree

10 files changed

+552
-330
lines changed

10 files changed

+552
-330
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Latte (https://latte.nette.org)
5+
* Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Latte\Compiler\Nodes\Php;
11+
12+
use Latte\Compiler\Node;
13+
use Latte\Compiler\Position;
14+
use Latte\Compiler\PrintContext;
15+
16+
17+
class ArgumentPlaceholderNode extends Node
18+
{
19+
public function __construct(
20+
public ?IdentifierNode $name = null,
21+
public ?Position $position = null,
22+
) {
23+
}
24+
25+
26+
public function print(PrintContext $context): string
27+
{
28+
return ($this->name ? $this->name . ': ' : '') . '?';
29+
}
30+
31+
32+
public function &getIterator(): \Generator
33+
{
34+
if ($this->name) {
35+
yield $this->name;
36+
}
37+
}
38+
}

src/Latte/Compiler/Nodes/Php/Expression/FunctionCallNode.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,23 @@ class FunctionCallNode extends ExpressionNode
2121
{
2222
public function __construct(
2323
public NameNode|ExpressionNode $name,
24-
/** @var array<Php\ArgumentNode|Php\VariadicPlaceholderNode> */
24+
/** @var array<Php\ArgumentNode|Php\VariadicPlaceholderNode|Php\ArgumentPlaceholderNode> */
2525
public array $args = [],
2626
public ?Position $position = null,
2727
) {
28-
(function (Php\ArgumentNode|Php\VariadicPlaceholderNode ...$args) {})(...$args);
28+
(function (Php\ArgumentNode|Php\VariadicPlaceholderNode|Php\ArgumentPlaceholderNode ...$args) {})(...$args);
2929
}
3030

3131

3232
public function isPartialFunction(): bool
3333
{
34-
return ($this->args[0] ?? null) instanceof Php\VariadicPlaceholderNode;
34+
return Helpers::isPartialFunction($this->args);
3535
}
3636

3737

3838
public function print(PrintContext $context): string
3939
{
40-
return $context->callExpr($this->name)
41-
. '(' . $context->implode($this->args) . ')';
40+
return $context->callPartial($context->callExpr($this->name), $this->args);
4241
}
4342

4443

src/Latte/Compiler/Nodes/Php/Expression/MethodCallNode.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@ class MethodCallNode extends ExpressionNode
2323
public function __construct(
2424
public ExpressionNode $object,
2525
public IdentifierNode|ExpressionNode $name,
26-
/** @var array<Php\ArgumentNode|Php\VariadicPlaceholderNode> */
26+
/** @var array<Php\ArgumentNode|Php\VariadicPlaceholderNode|Php\ArgumentPlaceholderNode> */
2727
public array $args = [],
2828
public bool $nullsafe = false,
2929
public ?Position $position = null,
3030
) {
31-
(function (Php\ArgumentNode|Php\VariadicPlaceholderNode ...$args) {})(...$args);
31+
(function (Php\ArgumentNode|Php\VariadicPlaceholderNode|Php\ArgumentPlaceholderNode ...$args) {})(...$args);
3232
}
3333

3434

3535
public function isPartialFunction(): bool
3636
{
37-
return ($this->args[0] ?? null) instanceof Php\VariadicPlaceholderNode;
37+
return Helpers::isPartialFunction($this->args);
3838
}
3939

4040

@@ -43,10 +43,12 @@ public function print(PrintContext $context): string
4343
if ($this->nullsafe && $this->isPartialFunction()) {
4444
throw new CompileException('Cannot combine nullsafe operator with Closure creation', $this->position);
4545
}
46-
return $context->dereferenceExpr($this->object)
47-
. ($this->nullsafe ? '?->' : '->')
48-
. $context->objectProperty($this->name)
49-
. '(' . $context->implode($this->args) . ')';
46+
return $context->callPartial(
47+
$context->dereferenceExpr($this->object)
48+
. ($this->nullsafe ? '?->' : '->')
49+
. $context->objectProperty($this->name),
50+
$this->args,
51+
);
5052
}
5153

5254

src/Latte/Compiler/Nodes/Php/Expression/StaticMethodCallNode.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,17 @@ class StaticMethodCallNode extends ExpressionNode
2323
public function __construct(
2424
public NameNode|ExpressionNode $class,
2525
public IdentifierNode|ExpressionNode $name,
26-
/** @var array<Php\ArgumentNode|Php\VariadicPlaceholderNode> */
26+
/** @var array<Php\ArgumentNode|Php\VariadicPlaceholderNode|Php\ArgumentPlaceholderNode> */
2727
public array $args = [],
2828
public ?Position $position = null,
2929
) {
30-
(function (Php\ArgumentNode|Php\VariadicPlaceholderNode ...$args) {})(...$args);
30+
(function (Php\ArgumentNode|Php\VariadicPlaceholderNode|Php\ArgumentPlaceholderNode ...$args) {})(...$args);
3131
}
3232

3333

3434
public function isPartialFunction(): bool
3535
{
36-
return ($this->args[0] ?? null) instanceof Php\VariadicPlaceholderNode;
36+
return Helpers::isPartialFunction($this->args);
3737
}
3838

3939

@@ -44,10 +44,10 @@ public function print(PrintContext $context): string
4444
$this->name instanceof ExpressionNode => '{' . $this->name->print($context) . '}',
4545
default => $this->name,
4646
};
47-
return $context->dereferenceExpr($this->class)
48-
. '::'
49-
. $name
50-
. '(' . $context->implode($this->args) . ')';
47+
return $context->callPartial(
48+
$context->dereferenceExpr($this->class) . '::' . $name,
49+
$this->args,
50+
);
5151
}
5252

5353

src/Latte/Compiler/PrintContext.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,30 @@ public function callExpr(Node $expr): string
238238
}
239239

240240

241+
public function callPartial(string $expr, array $args): string
242+
{
243+
$params = $pArgs = [];
244+
foreach ($args as $arg) {
245+
if ($arg instanceof Nodes\ArgumentNode) {
246+
$pArgs[] = $arg->print($this);
247+
} elseif ($arg instanceof Nodes\VariadicPlaceholderNode) {
248+
if (!$pArgs) {
249+
$pArgs[] = '...';
250+
} else {
251+
$params[] = $var = '$__' . count($params);
252+
$pArgs[] = '...' . $var;
253+
}
254+
} elseif ($arg instanceof Nodes\ArgumentPlaceholderNode) {
255+
$params[] = $var = '$__' . count($params);
256+
$pArgs[] = ($arg->name ? $arg->name . ': ' : '') . $var;
257+
}
258+
}
259+
260+
$expr .= '(' . implode(', ', $pArgs) . ')';
261+
return $params ? '(static fn(' . implode(', ', $params) . ') => ' . $expr . ')' : $expr;
262+
}
263+
264+
241265
/**
242266
* Wraps the LHS of a dereferencing operation in parentheses if needed.
243267
*/

0 commit comments

Comments
 (0)