Skip to content

Commit

Permalink
added nullsafe pipe operator ?|
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Jan 9, 2024
1 parent 6edb03d commit 8f3c972
Show file tree
Hide file tree
Showing 12 changed files with 707 additions and 330 deletions.
20 changes: 18 additions & 2 deletions src/Latte/Compiler/Nodes/Php/Expression/FilterCallNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,25 @@ public function __construct(
}


public function print(PrintContext $context): string
public function print(PrintContext $context, ?callable $outer = null): string
{
return $this->filter->printSimple($context, $this->expr->print($context));
$outer ??= fn($x) => $x;
return $this->expr instanceof self
? $this->expr->print(
$context,
fn(string $expr) => $this->printExpr($context, $expr, $outer)
)
: $this->printExpr($context, $this->expr->print($context), $outer);
}


private function printExpr(PrintContext $context, string $expr, callable $outer): string
{
return $this->filter->nullsafe
? '(($ʟ_fv = ' . $expr . ') === null ? null : '
. $outer($this->filter->printSimple($context, '$ʟ_fv'))
. ')'
: $outer($this->filter->printSimple($context, $expr));
}


Expand Down
1 change: 1 addition & 0 deletions src/Latte/Compiler/Nodes/Php/FilterNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public function __construct(
public IdentifierNode $name,
/** @var ArgumentNode[] */
public array $args = [],
public bool $nullsafe = false,
public ?Position $position = null,
) {
(function (ArgumentNode ...$args) {})(...$args);
Expand Down
1 change: 1 addition & 0 deletions src/Latte/Compiler/TagLexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ private function tokenizeCode(): void
(?<Php_PowEqual> \*\*= )|
(?<Php_CoalesceEqual> \?\?= )|
(?<Php_Coalesce> \?\? )|
(?<Php_NullsafePipe> \?\| )|
(?<Php_BooleanOr> \|\| )|
(?<Php_BooleanAnd> && )|
(?<Php_AmpersandFollowed> & (?= [ \t\r\n]* (\$|\.\.\.) ) )|
Expand Down
657 changes: 332 additions & 325 deletions src/Latte/Compiler/TagParserData.php

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/Latte/Compiler/Token.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ final class Token
Php_Comment = 334,
Php_Null = 335,
Php_True = 336,
Php_False = 337;
Php_False = 337,
Php_NullsafePipe = 338;

public const Names = [
self::End => '[EOF]',
Expand Down Expand Up @@ -224,6 +225,7 @@ final class Token
self::Php_Null => "'null'",
self::Php_True => "'true'",
self::Php_False => "'false'",
self::Php_NullsafePipe => "'?|'",
];


Expand Down
6 changes: 6 additions & 0 deletions tests/common/TagParser.parseArguments().phpt
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ test('inline modifiers', function () {
});


test('inline nullsafe pipe', function () {
Assert::same('(($ʟ_fv = 0) === null ? null : ($this->filters->mod)($ʟ_fv))', formatArgs('(0?|mod)'));
Assert::same('(($ʟ_fv = 0) === null ? null : (($ʟ_fv = ($this->filters->mod2)(($this->filters->mod1)($ʟ_fv))) === null ? null : ($this->filters->mod3)($ʟ_fv)))', formatArgs('(0?|mod1|mod2?|mod3)'));
});


test('in operator', function () {
Assert::same("in_array(\$a, ['a', 'b'], true), 1", formatArgs('$a in [a, b], 1'));
Assert::same('$a, in_array($b->func(), [1, 2], true)', formatArgs('$a, $b->func() in [1, 2]'));
Expand Down
4 changes: 4 additions & 0 deletions tests/common/TagParser.parseModifier().phpt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ test('depth', function () {
});


test('nullsafe pipe', function () {
Assert::same('(($ʟ_fv = @) === null ? null : (($ʟ_fv = ($this->filters->mod2)(($this->filters->mod1)($ʟ_fv))) === null ? null : ($this->filters->mod3)($ʟ_fv)))', format('?|mod1|mod2?|mod3'));
});

test('optionalChainingPass', function () {
Assert::same(
'($this->filters->mod)(@, $var?->prop?->elem[1]?->call(2)?->item)',
Expand Down
10 changes: 10 additions & 0 deletions tests/phpParser/filters.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode
| | | | | name: 'upper'
| | | | | position: 1:5 (offset 4)
| | | | args: array (0)
| | | | nullsafe: false
| | | | position: 1:2 (offset 1)
| | | position: 1:2 (offset 1)
| | key: null
Expand All @@ -60,13 +61,15 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode
| | | | | | name: 'upper'
| | | | | | position: 2:11 (offset 22)
| | | | | args: array (0)
| | | | | nullsafe: false
| | | | | position: 2:2 (offset 13)
| | | | position: 2:2 (offset 13)
| | | filter: Latte\Compiler\Nodes\Php\FilterNode
| | | | name: Latte\Compiler\Nodes\Php\IdentifierNode
| | | | | name: 'truncate'
| | | | | position: 2:17 (offset 28)
| | | | args: array (0)
| | | | nullsafe: false
| | | | position: 2:2 (offset 13)
| | | position: 2:2 (offset 13)
| | key: null
Expand Down Expand Up @@ -102,13 +105,15 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode
| | | | | | | unpack: false
| | | | | | | name: null
| | | | | | | position: 3:20 (offset 58)
| | | | | nullsafe: false
| | | | | position: 3:2 (offset 40)
| | | | position: 3:2 (offset 40)
| | | filter: Latte\Compiler\Nodes\Php\FilterNode
| | | | name: Latte\Compiler\Nodes\Php\IdentifierNode
| | | | | name: 'trim'
| | | | | position: 3:23 (offset 61)
| | | | args: array (0)
| | | | nullsafe: false
| | | | position: 3:2 (offset 40)
| | | position: 3:2 (offset 40)
| | key: null
Expand Down Expand Up @@ -146,19 +151,22 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode
| | | | | | | | | | name: 'round'
| | | | | | | | | | position: 4:24 (offset 91)
| | | | | | | | | args: array (0)
| | | | | | | | | nullsafe: false
| | | | | | | | | position: 4:21 (offset 88)
| | | | | | | | position: 4:21 (offset 88)
| | | | | | | byRef: false
| | | | | | | unpack: false
| | | | | | | name: null
| | | | | | | position: 4:20 (offset 87)
| | | | | nullsafe: false
| | | | | position: 4:2 (offset 69)
| | | | position: 4:2 (offset 69)
| | | filter: Latte\Compiler\Nodes\Php\FilterNode
| | | | name: Latte\Compiler\Nodes\Php\IdentifierNode
| | | | | name: 'trim'
| | | | | position: 4:31 (offset 98)
| | | | args: array (0)
| | | | nullsafe: false
| | | | position: 4:2 (offset 69)
| | | position: 4:2 (offset 69)
| | key: null
Expand Down Expand Up @@ -196,6 +204,7 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode
| | | | | | | name: 'b'
| | | | | | | position: 5:23 (offset 127)
| | | | | | position: 5:23 (offset 127)
| | | | nullsafe: false
| | | | position: 5:2 (offset 106)
| | | position: 5:2 (offset 106)
| | key: null
Expand Down Expand Up @@ -233,6 +242,7 @@ Latte\Compiler\Nodes\Php\Expression\ArrayNode
| | | | | | | name: 'b'
| | | | | | | position: 6:23 (offset 159)
| | | | | | position: 6:23 (offset 159)
| | | | nullsafe: false
| | | | position: 6:2 (offset 138)
| | | position: 6:2 (offset 138)
| | key: null
Expand Down
Loading

0 comments on commit 8f3c972

Please sign in to comment.