Add support for argument unpacking

This commit is contained in:
Fabien Potencier
2024-09-10 23:40:39 +02:00
parent 1a20e96174
commit 112de8dcfa
6 changed files with 66 additions and 3 deletions
+1
View File
@@ -1,5 +1,6 @@
# 3.15.0 (2024-XX-XX)
* Add support for argument unpackaging
* Add JSON support for the file extension escaping strategy
* Support Markup instances (and any other \Stringable) as dynamic mapping keys
* Deprecate the `sandbox` tag
+9 -2
View File
@@ -815,14 +815,21 @@ The following operators don't fit into any of the other categories:
{# returns the value of foo if it is defined and not null, 'no' otherwise #}
{{ foo ?? 'no' }}
* ``...``: The spread operator can be used to expand sequences or mappings (it
cannot be used to expand the arguments of a function call):
* ``...``: The spread operator can be used to expand sequences or mappings or
to expand the arguments of a function call:
.. code-block:: twig
{% set numbers = [1, 2, ...moreNumbers] %}
{% set ratings = {'foo': 10, 'bar': 5, ...moreRatings} %}
{{ 'Hello %s %s!'|format(...['Fabien', 'Potencier']) }}
.. versionadded:: 3.15
Support for expanding the arguments of a function call was introduced in
Twig 3.15.
Operators
~~~~~~~~~
+10 -1
View File
@@ -30,6 +30,7 @@ use Twig\Node\Expression\Unary\AbstractUnary;
use Twig\Node\Expression\Unary\NegUnary;
use Twig\Node\Expression\Unary\NotUnary;
use Twig\Node\Expression\Unary\PosUnary;
use Twig\Node\Expression\Unary\SpreadUnary;
use Twig\Node\Node;
/**
@@ -618,6 +619,7 @@ class ExpressionParser
$stream = $this->parser->getStream();
$stream->expect(Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
$hasSpread = false;
while (!$stream->test(Token::PUNCTUATION_TYPE, ')')) {
if ($args) {
$stream->expect(Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
@@ -632,7 +634,14 @@ class ExpressionParser
$token = $stream->expect(Token::NAME_TYPE, null, 'An argument must be a name');
$value = new NameExpression($token->getValue(), $this->parser->getCurrentToken()->getLine());
} else {
$value = $this->parseExpression(0, $allowArrow);
if ($stream->nextIf(Token::SPREAD_TYPE)) {
$hasSpread = true;
$value = new SpreadUnary($this->parseExpression(0, $allowArrow), $stream->getCurrent()->getLine());
} elseif ($hasSpread) {
throw new SyntaxError('Normal arguments must be placed before argument unpacking.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
} else {
$value = $this->parseExpression(0, $allowArrow);
}
}
$name = null;
+22
View File
@@ -0,0 +1,22 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Twig\Node\Expression\Unary;
use Twig\Compiler;
final class SpreadUnary extends AbstractUnary
{
public function operator(Compiler $compiler): Compiler
{
return $compiler->raw('...');
}
}
@@ -0,0 +1,16 @@
--TEST--
Twig supports array unpacking for function calls
--TEMPLATE--
{{ '%s %s %s'|format(...[1, 2, 3]) }}
{{ '%s %s %s'|format(...[1], ...[2, 3]) }}
{{ '%s %s %s'|format(1, ...[2, 3]) }}
{{ '%s %s %s'|format(1, ...[2], ...[3]) }}
{{ '%s %s %s'|format(...it) }}
--DATA--
return ['it' => new \ArrayIterator([1, 2, 3])]
--EXPECT--
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
@@ -0,0 +1,8 @@
--TEST--
Twig supports array unpacking for function calls (but not before normal args)
--TEMPLATE--
{{ '%s %s %s'|format(...[1, 2], 3) }}
--DATA--
return []
--EXCEPTION--
Twig\Error\SyntaxError: Normal arguments must be placed before argument unpacking in "index.twig" at line 2.