enhanced the for-loop optimizer pass 2 (patch from nikic)

This commit is contained in:
Fabien Potencier
2010-12-13 15:46:09 +01:00
parent e0f20a0c4d
commit 8cd9bcb775
2 changed files with 45 additions and 16 deletions
+40 -12
View File
@@ -86,19 +86,35 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
// disable the loop variable by default
$node->setAttribute('with_loop', false);
array_unshift($this->loops, $node);
} elseif ($this->loops
// when do we need to add the loop variable back?
&& (
// the loop variable is referenced here
($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name'))
||
// include without the only attribute
($this->loops && $node instanceof Twig_Node_Include && !$node->getAttribute('only'))
)
} elseif (!$this->loops) {
// we are outside a loop
return;
}
// when do we need to add the loop variable back?
// the loop variable is referenced for the current loop
elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
$this->addLoopToCurrent();
}
// include without the only attribute
elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) {
$this->addLoopToAll();
}
// the loop variable is referenced via an attribute
elseif ($node instanceof Twig_Node_Expression_GetAttr
&& (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant
|| 'parent' === $node->getNode('attribute')->getAttribute('value')
)
&& (true === $this->loops[0]->getAttribute('with_loop')
|| ($node->getNode('node') instanceof Twig_Node_Expression_Name
&& 'loop' === $node->getNode('node')->getAttribute('name')
)
)
) {
foreach ($this->loops as $loop) {
$loop->setAttribute('with_loop', true);
}
$this->addLoopToAll();
}
}
@@ -109,6 +125,18 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
}
}
protected function addLoopToCurrent()
{
$this->loops[0]->setAttribute('with_loop', true);
}
protected function addLoopToAll()
{
foreach ($this->loops as $loop) {
$loop->setAttribute('with_loop', true);
}
}
/**
* {@inheritdoc}
*/
@@ -21,7 +21,7 @@ class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase
$stream = $env->parse($env->tokenize($template, 'index'));
foreach ($expected as $target => $withLoop) {
$this->assertTrue($this->checkForConfiguration($stream, $target, $withLoop));
$this->assertTrue($this->checkForConfiguration($stream, $target, $withLoop), sprintf('variable %s is %soptimized', $target, $withLoop ? 'not ' : ''));
}
}
@@ -38,12 +38,13 @@ class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase
array('{% for i in foo %}{% include "foo" only %}{% endfor %}', array('i' => false)),
// "i" should be false
array('{% for i in foo %}{% for j in foo %}{{ loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)),
array('{% for i in foo %}{% for j in foo %}{{ loop.index }}{% endfor %}{% endfor %}', array('i' => false, 'j' => true)),
array('{% for i in foo %}{% for j in foo %}{{ loop.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)),
//array('{% for i in foo %}{% for j in foo %}{{ foo.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => false, 'j' => false)),
array('{% for i in foo %}{% set l = loop %}{% for j in foo %}{{ l.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => false)),
array('{% for i in foo %}{% for j in foo %}{{ foo.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => false, 'j' => false)),
array('{% for i in foo %}{% for j in foo %}{{ loop["parent"].loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)),
);