Skip to content

Commit

Permalink
Add TypesTokenParser
Browse files Browse the repository at this point in the history
  • Loading branch information
drjayvee committed Aug 27, 2024
1 parent 2dc48a3 commit ceb4749
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Extension/CoreExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
use Twig\TokenParser\IncludeTokenParser;
use Twig\TokenParser\MacroTokenParser;
use Twig\TokenParser\SetTokenParser;
use Twig\TokenParser\TypesTokenParser;
use Twig\TokenParser\UseTokenParser;
use Twig\TokenParser\WithTokenParser;
use Twig\TwigFilter;
Expand Down Expand Up @@ -182,6 +183,7 @@ public function getTokenParsers(): array
new ImportTokenParser(),
new FromTokenParser(),
new SetTokenParser(),
new TypesTokenParser(),
new FlushTokenParser(),
new DoTokenParser(),
new EmbedTokenParser(),
Expand Down
2 changes: 2 additions & 0 deletions src/Node/TypesNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Twig\Node;

use Twig\Attribute\YieldReady;
use Twig\Compiler;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ConstantExpression;
Expand All @@ -13,6 +14,7 @@
* @author Jeroen Versteeg <[email protected]>
* @see https://github.com/twigphp/Twig/issues/4165
*/
#[YieldReady]
class TypesNode extends Node implements NodeCaptureInterface
{
public function __construct(ArrayExpression $typesNode, int $lineno, ?string $tag = null)
Expand Down
88 changes: 88 additions & 0 deletions src/TokenParser/TypesTokenParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?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\TokenParser;

use Twig\Error\SyntaxError;
use Twig\ExpressionParser;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\NameExpression;
use Twig\Node\Node;
use Twig\Node\SetNode;
use Twig\Node\TypesNode;
use Twig\Token;
use Twig\TokenStream;

/**
* Declare variable types.
*
* {% types {foo: 'int', bar: 'string'} %}
*
* @author Jeroen Versteeg <[email protected]>
* @see https://github.com/twigphp/Twig/issues/4165
* @internal
*/
final class TypesTokenParser extends AbstractTokenParser
{
public function parse(Token $token): Node
{
$stream = $this->parser->getStream();

$expression = $this->parseSimpleMappingExpression($stream);

$stream->expect(Token::BLOCK_END_TYPE);

return new TypesNode($expression, $token->getLine(), $this->getTag());
}

/**
* @throws SyntaxError
* @see ExpressionParser::parseMappingExpression()
*/
private function parseSimpleMappingExpression(TokenStream $stream): ArrayExpression
{
$stream->expect(Token::PUNCTUATION_TYPE, '{', 'A mapping element was expected');

$node = new ArrayExpression([], $stream->getCurrent()->getLine());

$first = true;
while (!$stream->test(Token::PUNCTUATION_TYPE, '}')) {
if (!$first) {
$stream->expect(Token::PUNCTUATION_TYPE, ',', 'A mapping value must be followed by a comma');

// trailing ,?
if ($stream->test(Token::PUNCTUATION_TYPE, '}')) {
break;
}
}
$first = false;

$nameToken = $stream->expect(Token::NAME_TYPE);
$nameExpression = new NameExpression($nameToken->getValue(), $nameToken->getLine());

$stream->expect(Token::PUNCTUATION_TYPE, ':', 'A mapping key must be followed by a colon (:)');

$valueToken = $stream->expect(Token::STRING_TYPE);
$valueExpression = new ConstantExpression($valueToken->getValue(), $valueToken->getLine());

$node->addElement($valueExpression, $nameExpression);
}
$stream->expect(Token::PUNCTUATION_TYPE, '}', 'An opened mapping is not properly closed');

return $node;
}

public function getTag(): string
{
return 'types';
}
}

0 comments on commit ceb4749

Please sign in to comment.