Skip to content

Commit

Permalink
feature twigphp#3959 Optimize TextNodes (fabpot)
Browse files Browse the repository at this point in the history
This PR was merged into the 3.x branch.

Discussion
----------

Optimize TextNodes

Not a great perf optimization, but it makes the node graph simpler which helps when we need to debug templates.

Commits
-------

c44bd1f Optimize TextNodes
  • Loading branch information
fabpot committed Jan 11, 2024
2 parents cccf8b7 + c44bd1f commit 433189b
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 3 deletions.
43 changes: 43 additions & 0 deletions src/NodeVisitor/OptimizerNodeVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use Twig\Node\IncludeNode;
use Twig\Node\Node;
use Twig\Node\PrintNode;
use Twig\Node\TextNode;

/**
* Tries to optimize the AST.
Expand All @@ -43,6 +44,7 @@ final class OptimizerNodeVisitor implements NodeVisitorInterface
public const OPTIMIZE_NONE = 0;
public const OPTIMIZE_FOR = 2;
public const OPTIMIZE_RAW_FILTER = 4;
public const OPTIMIZE_TEXT_NODES = 8;

private $loops = [];
private $loopsTargets = [];
Expand Down Expand Up @@ -81,6 +83,42 @@ public function leaveNode(Node $node, Environment $env): ?Node

$node = $this->optimizePrintNode($node);

if (self::OPTIMIZE_TEXT_NODES === (self::OPTIMIZE_TEXT_NODES & $this->optimizers)) {
$node = $this->mergeTextNodeCalls($node);
}

return $node;
}

private function mergeTextNodeCalls(Node $node): Node
{
$text = '';
$names = [];
foreach ($node as $k => $n) {
if (!$n instanceof TextNode) {
return $node;
}

$text .= $n->getAttribute('data');
$names[] = $k;
}

if (!$text) {
return $node;
}

if (Node::class === get_class($node)) {
return new TextNode($text, $node->getTemplateLine());
}

foreach ($names as $i => $name) {
if (0 === $i) {
$node->setNode($name, new TextNode($text, $node->getTemplateLine()));
} else {
$node->removeNode($name);
}
}

return $node;
}

Expand All @@ -98,6 +136,11 @@ private function optimizePrintNode(Node $node): Node
}

$exprNode = $node->getNode('expr');

if ($exprNode instanceof ConstantExpression && is_string($exprNode->getAttribute('value'))) {
return new TextNode($exprNode->getAttribute('value'), $exprNode->getTemplateLine());
}

if (
$exprNode instanceof BlockReferenceExpression
|| $exprNode instanceof ParentExpression
Expand Down
3 changes: 0 additions & 3 deletions tests/ExpressionParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,6 @@ public function testStringExpression($template, $expected)
public function getTestsForString()
{
return [
[
'{{ "foo" }}', new ConstantExpression('foo', 1),
],
[
'{{ "foo #{bar}" }}', new ConcatBinary(
new ConstantExpression('foo ', 1),
Expand Down

0 comments on commit 433189b

Please sign in to comment.