PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/all-in-one-event-calendar/vendor/twig/NodeVisitor/Optimizer.php

https://github.com/dedavidd/piratenpartij.nl
PHP | 246 lines | 145 code | 34 blank | 67 comment | 37 complexity | ccfdba7eab59af6817be00f9e24152db MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, GPL-3.0
  1. <?php
  2. /*
  3. * This file is part of Twig.
  4. *
  5. * (c) 2010 Fabien Potencier
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. /**
  11. * Twig_NodeVisitor_Optimizer tries to optimizes the AST.
  12. *
  13. * This visitor is always the last registered one.
  14. *
  15. * You can configure which optimizations you want to activate via the
  16. * optimizer mode.
  17. *
  18. * @author Fabien Potencier <fabien@symfony.com>
  19. */
  20. class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
  21. {
  22. const OPTIMIZE_ALL = -1;
  23. const OPTIMIZE_NONE = 0;
  24. const OPTIMIZE_FOR = 2;
  25. const OPTIMIZE_RAW_FILTER = 4;
  26. const OPTIMIZE_VAR_ACCESS = 8;
  27. protected $loops = array();
  28. protected $optimizers;
  29. protected $prependedNodes = array();
  30. protected $inABody = false;
  31. /**
  32. * Constructor.
  33. *
  34. * @param integer $optimizers The optimizer mode
  35. */
  36. public function __construct($optimizers = -1)
  37. {
  38. if (!is_int($optimizers) || $optimizers > 2) {
  39. throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers));
  40. }
  41. $this->optimizers = $optimizers;
  42. }
  43. /**
  44. * {@inheritdoc}
  45. */
  46. public function enterNode(Twig_NodeInterface $node, Twig_Environment $env)
  47. {
  48. if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
  49. $this->enterOptimizeFor($node, $env);
  50. }
  51. if (!version_compare(phpversion(), '5.4.0RC1', '>=') && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
  52. if ($this->inABody) {
  53. if (!$node instanceof Twig_Node_Expression) {
  54. if (get_class($node) !== 'Twig_Node') {
  55. array_unshift($this->prependedNodes, array());
  56. }
  57. } else {
  58. $node = $this->optimizeVariables($node, $env);
  59. }
  60. } elseif ($node instanceof Twig_Node_Body) {
  61. $this->inABody = true;
  62. }
  63. }
  64. return $node;
  65. }
  66. /**
  67. * {@inheritdoc}
  68. */
  69. public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env)
  70. {
  71. $expression = $node instanceof Twig_Node_Expression;
  72. if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) {
  73. $this->leaveOptimizeFor($node, $env);
  74. }
  75. if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) {
  76. $node = $this->optimizeRawFilter($node, $env);
  77. }
  78. $node = $this->optimizePrintNode($node, $env);
  79. if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) {
  80. if ($node instanceof Twig_Node_Body) {
  81. $this->inABody = false;
  82. } elseif ($this->inABody) {
  83. if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) {
  84. $nodes = array();
  85. foreach (array_unique($prependedNodes) as $name) {
  86. $nodes[] = new Twig_Node_SetTemp($name, $node->getLine());
  87. }
  88. $nodes[] = $node;
  89. $node = new Twig_Node($nodes);
  90. }
  91. }
  92. }
  93. return $node;
  94. }
  95. protected function optimizeVariables(Twig_NodeInterface $node, Twig_Environment $env)
  96. {
  97. if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) {
  98. $this->prependedNodes[0][] = $node->getAttribute('name');
  99. return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getLine());
  100. }
  101. return $node;
  102. }
  103. /**
  104. * Optimizes print nodes.
  105. *
  106. * It replaces:
  107. *
  108. * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()"
  109. *
  110. * @param Twig_NodeInterface $node A Node
  111. * @param Twig_Environment $env The current Twig environment
  112. */
  113. protected function optimizePrintNode(Twig_NodeInterface $node, Twig_Environment $env)
  114. {
  115. if (!$node instanceof Twig_Node_Print) {
  116. return $node;
  117. }
  118. if (
  119. $node->getNode('expr') instanceof Twig_Node_Expression_BlockReference ||
  120. $node->getNode('expr') instanceof Twig_Node_Expression_Parent
  121. ) {
  122. $node->getNode('expr')->setAttribute('output', true);
  123. return $node->getNode('expr');
  124. }
  125. return $node;
  126. }
  127. /**
  128. * Removes "raw" filters.
  129. *
  130. * @param Twig_NodeInterface $node A Node
  131. * @param Twig_Environment $env The current Twig environment
  132. */
  133. protected function optimizeRawFilter(Twig_NodeInterface $node, Twig_Environment $env)
  134. {
  135. if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) {
  136. return $node->getNode('node');
  137. }
  138. return $node;
  139. }
  140. /**
  141. * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
  142. *
  143. * @param Twig_NodeInterface $node A Node
  144. * @param Twig_Environment $env The current Twig environment
  145. */
  146. protected function enterOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
  147. {
  148. if ($node instanceof Twig_Node_For) {
  149. // disable the loop variable by default
  150. $node->setAttribute('with_loop', false);
  151. array_unshift($this->loops, $node);
  152. } elseif (!$this->loops) {
  153. // we are outside a loop
  154. return;
  155. }
  156. // when do we need to add the loop variable back?
  157. // the loop variable is referenced for the current loop
  158. elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
  159. $this->addLoopToCurrent();
  160. }
  161. // block reference
  162. elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) {
  163. $this->addLoopToCurrent();
  164. }
  165. // include without the only attribute
  166. elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) {
  167. $this->addLoopToAll();
  168. }
  169. // the loop variable is referenced via an attribute
  170. elseif ($node instanceof Twig_Node_Expression_GetAttr
  171. && (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant
  172. || 'parent' === $node->getNode('attribute')->getAttribute('value')
  173. )
  174. && (true === $this->loops[0]->getAttribute('with_loop')
  175. || ($node->getNode('node') instanceof Twig_Node_Expression_Name
  176. && 'loop' === $node->getNode('node')->getAttribute('name')
  177. )
  178. )
  179. ) {
  180. $this->addLoopToAll();
  181. }
  182. }
  183. /**
  184. * Optimizes "for" tag by removing the "loop" variable creation whenever possible.
  185. *
  186. * @param Twig_NodeInterface $node A Node
  187. * @param Twig_Environment $env The current Twig environment
  188. */
  189. protected function leaveOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env)
  190. {
  191. if ($node instanceof Twig_Node_For) {
  192. array_shift($this->loops);
  193. }
  194. }
  195. protected function addLoopToCurrent()
  196. {
  197. $this->loops[0]->setAttribute('with_loop', true);
  198. }
  199. protected function addLoopToAll()
  200. {
  201. foreach ($this->loops as $loop) {
  202. $loop->setAttribute('with_loop', true);
  203. }
  204. }
  205. /**
  206. * {@inheritdoc}
  207. */
  208. public function getPriority()
  209. {
  210. return 255;
  211. }
  212. }