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