Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Parser.php

Zuletzt modifiziert: 02.04.2025, 15:03 - Dateigröße: 12.71 KiB


001  <?php
002   
003  /*
004   * This file is part of Twig.
005   *
006   * (c) Fabien Potencier
007   * (c) Armin Ronacher
008   *
009   * For the full copyright and license information, please view the LICENSE
010   * file that was distributed with this source code.
011   */
012   
013  namespace Twig;
014   
015  use Twig\Error\SyntaxError;
016  use Twig\Node\BlockNode;
017  use Twig\Node\BlockReferenceNode;
018  use Twig\Node\BodyNode;
019  use Twig\Node\Expression\AbstractExpression;
020  use Twig\Node\MacroNode;
021  use Twig\Node\ModuleNode;
022  use Twig\Node\Node;
023  use Twig\Node\NodeCaptureInterface;
024  use Twig\Node\NodeOutputInterface;
025  use Twig\Node\PrintNode;
026  use Twig\Node\SpacelessNode;
027  use Twig\Node\TextNode;
028  use Twig\TokenParser\TokenParserInterface;
029   
030  /**
031   * Default parser implementation.
032   *
033   * @author Fabien Potencier <fabien@symfony.com>
034   */
035  class Parser
036  {
037      private $stack = [];
038      private $stream;
039      private $parent;
040      private $handlers;
041      private $visitors;
042      private $expressionParser;
043      private $blocks;
044      private $blockStack;
045      private $macros;
046      private $env;
047      private $importedSymbols;
048      private $traits;
049      private $embeddedTemplates = [];
050      private $varNameSalt = 0;
051   
052      public function __construct(Environment $env)
053      {
054          $this->env = $env;
055      }
056   
057      public function getVarName()
058      {
059          return sprintf('__internal_parse_%d', $this->varNameSalt++);
060      }
061   
062      public function parse(TokenStream $stream, $test = null, $dropNeedle = false)
063      {
064          $vars = get_object_vars($this);
065          unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames'], $vars['varNameSalt']);
066          $this->stack[] = $vars;
067   
068          // tag handlers
069          if (null === $this->handlers) {
070              $this->handlers = [];
071              foreach ($this->env->getTokenParsers() as $handler) {
072                  $handler->setParser($this);
073   
074                  $this->handlers[$handler->getTag()] = $handler;
075              }
076          }
077   
078          // node visitors
079          if (null === $this->visitors) {
080              $this->visitors = $this->env->getNodeVisitors();
081          }
082   
083          if (null === $this->expressionParser) {
084              $this->expressionParser = new ExpressionParser($this, $this->env);
085          }
086   
087          $this->stream = $stream;
088          $this->parent = null;
089          $this->blocks = [];
090          $this->macros = [];
091          $this->traits = [];
092          $this->blockStack = [];
093          $this->importedSymbols = [[]];
094          $this->embeddedTemplates = [];
095   
096          try {
097              $body = $this->subparse($test, $dropNeedle);
098   
099              if (null !== $this->parent && null === $body = $this->filterBodyNodes($body)) {
100                  $body = new Node();
101              }
102          } catch (SyntaxError $e) {
103              if (!$e->getSourceContext()) {
104                  $e->setSourceContext($this->stream->getSourceContext());
105              }
106   
107              if (!$e->getTemplateLine()) {
108                  $e->setTemplateLine($this->stream->getCurrent()->getLine());
109              }
110   
111              throw $e;
112          }
113   
114          $node = new ModuleNode(new BodyNode([$body]), $this->parent, new Node($this->blocks), new Node($this->macros), new Node($this->traits), $this->embeddedTemplates, $stream->getSourceContext());
115   
116          $traverser = new NodeTraverser($this->env, $this->visitors);
117   
118          $node = $traverser->traverse($node);
119   
120          // restore previous stack so previous parse() call can resume working
121          foreach (array_pop($this->stack) as $key => $val) {
122              $this->$key = $val;
123          }
124   
125          return $node;
126      }
127   
128      public function subparse($test, $dropNeedle = false)
129      {
130          $lineno = $this->getCurrentToken()->getLine();
131          $rv = [];
132          while (!$this->stream->isEOF()) {
133              switch ($this->getCurrentToken()->getType()) {
134                  case /* Token::TEXT_TYPE */ 0:
135                      $token = $this->stream->next();
136                      $rv[] = new TextNode($token->getValue(), $token->getLine());
137                      break;
138   
139                  case /* Token::VAR_START_TYPE */ 2:
140                      $token = $this->stream->next();
141                      $expr = $this->expressionParser->parseExpression();
142                      $this->stream->expect(/* Token::VAR_END_TYPE */ 4);
143                      $rv[] = new PrintNode($expr, $token->getLine());
144                      break;
145   
146                  case /* Token::BLOCK_START_TYPE */ 1:
147                      $this->stream->next();
148                      $token = $this->getCurrentToken();
149   
150                      if (/* Token::NAME_TYPE */ 5 !== $token->getType()) {
151                          throw new SyntaxError('A block must start with a tag name.', $token->getLine(), $this->stream->getSourceContext());
152                      }
153   
154                      if (null !== $test && $test($token)) {
155                          if ($dropNeedle) {
156                              $this->stream->next();
157                          }
158   
159                          if (1 === \count($rv)) {
160                              return $rv[0];
161                          }
162   
163                          return new Node($rv, [], $lineno);
164                      }
165   
166                      if (!isset($this->handlers[$token->getValue()])) {
167                          if (null !== $test) {
168                              $e = new SyntaxError(sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->stream->getSourceContext());
169   
170                              if (\is_array($test) && isset($test[0]) && $test[0] instanceof TokenParserInterface) {
171                                  $e->appendMessage(sprintf(' (expecting closing tag for the "%s" tag defined near line %s).', $test[0]->getTag(), $lineno));
172                              }
173                          } else {
174                              $e = new SyntaxError(sprintf('Unknown "%s" tag.', $token->getValue()), $token->getLine(), $this->stream->getSourceContext());
175                              $e->addSuggestions($token->getValue(), array_keys($this->env->getTags()));
176                          }
177   
178                          throw $e;
179                      }
180   
181                      $this->stream->next();
182   
183                      $subparser = $this->handlers[$token->getValue()];
184                      $node = $subparser->parse($token);
185                      if (null !== $node) {
186                          $rv[] = $node;
187                      }
188                      break;
189   
190                  default:
191                      throw new SyntaxError('Lexer or parser ended up in unsupported state.', $this->getCurrentToken()->getLine(), $this->stream->getSourceContext());
192              }
193          }
194   
195          if (1 === \count($rv)) {
196              return $rv[0];
197          }
198   
199          return new Node($rv, [], $lineno);
200      }
201   
202      public function getBlockStack()
203      {
204          return $this->blockStack;
205      }
206   
207      public function peekBlockStack()
208      {
209          return isset($this->blockStack[\count($this->blockStack) - 1]) ? $this->blockStack[\count($this->blockStack) - 1] : null;
210      }
211   
212      public function popBlockStack()
213      {
214          array_pop($this->blockStack);
215      }
216   
217      public function pushBlockStack($name)
218      {
219          $this->blockStack[] = $name;
220      }
221   
222      public function hasBlock($name)
223      {
224          return isset($this->blocks[$name]);
225      }
226   
227      public function getBlock($name)
228      {
229          return $this->blocks[$name];
230      }
231   
232      public function setBlock($name, BlockNode $value)
233      {
234          $this->blocks[$name] = new BodyNode([$value], [], $value->getTemplateLine());
235      }
236   
237      public function hasMacro($name)
238      {
239          return isset($this->macros[$name]);
240      }
241   
242      public function setMacro($name, MacroNode $node)
243      {
244          $this->macros[$name] = $node;
245      }
246   
247      /**
248       * @deprecated since Twig 2.7 as there are no reserved macro names anymore, will be removed in 3.0.
249       */
250      public function isReservedMacroName($name)
251      {
252          @trigger_error(sprintf('The "%s" method is deprecated since Twig 2.7 and will be removed in 3.0.', __METHOD__), \E_USER_DEPRECATED);
253   
254          return false;
255      }
256   
257      public function addTrait($trait)
258      {
259          $this->traits[] = $trait;
260      }
261   
262      public function hasTraits()
263      {
264          return \count($this->traits) > 0;
265      }
266   
267      public function embedTemplate(ModuleNode $template)
268      {
269          $template->setIndex(mt_rand());
270   
271          $this->embeddedTemplates[] = $template;
272      }
273   
274      public function addImportedSymbol($type, $alias, $name = null, AbstractExpression $node = null)
275      {
276          $this->importedSymbols[0][$type][$alias] = ['name' => $name, 'node' => $node];
277      }
278   
279      public function getImportedSymbol($type, $alias)
280      {
281          // if the symbol does not exist in the current scope (0), try in the main/global scope (last index)
282          return $this->importedSymbols[0][$type][$alias] ?? ($this->importedSymbols[\count($this->importedSymbols) - 1][$type][$alias] ?? null);
283      }
284   
285      public function isMainScope()
286      {
287          return 1 === \count($this->importedSymbols);
288      }
289   
290      public function pushLocalScope()
291      {
292          array_unshift($this->importedSymbols, []);
293      }
294   
295      public function popLocalScope()
296      {
297          array_shift($this->importedSymbols);
298      }
299   
300      /**
301       * @return ExpressionParser
302       */
303      public function getExpressionParser()
304      {
305          return $this->expressionParser;
306      }
307   
308      public function getParent()
309      {
310          return $this->parent;
311      }
312   
313      public function setParent($parent)
314      {
315          $this->parent = $parent;
316      }
317   
318      /**
319       * @return TokenStream
320       */
321      public function getStream()
322      {
323          return $this->stream;
324      }
325   
326      /**
327       * @return Token
328       */
329      public function getCurrentToken()
330      {
331          return $this->stream->getCurrent();
332      }
333   
334      private function filterBodyNodes(Node $node, bool $nested = false)
335      {
336          // check that the body does not contain non-empty output nodes
337          if (
338              ($node instanceof TextNode && !ctype_space($node->getAttribute('data')))
339              ||
340              // the "&& !$node instanceof SpacelessNode" part of the condition must be removed in 3.0
341              (!$node instanceof TextNode && !$node instanceof BlockReferenceNode && ($node instanceof NodeOutputInterface && !$node instanceof SpacelessNode))
342          ) {
343              if (false !== strpos((string) $node, \chr(0xEF).\chr(0xBB).\chr(0xBF))) {
344                  $t = substr($node->getAttribute('data'), 3);
345                  if ('' === $t || ctype_space($t)) {
346                      // bypass empty nodes starting with a BOM
347                      return;
348                  }
349              }
350   
351              throw new SyntaxError('A template that extends another one cannot include content outside Twig blocks. Did you forget to put the content inside a {% block %} tag?', $node->getTemplateLine(), $this->stream->getSourceContext());
352          }
353   
354          // bypass nodes that "capture" the output
355          if ($node instanceof NodeCaptureInterface) {
356              // a "block" tag in such a node will serve as a block definition AND be displayed in place as well
357              return $node;
358          }
359   
360          // to be removed completely in Twig 3.0
361          if (!$nested && $node instanceof SpacelessNode) {
362              @trigger_error(sprintf('Using the spaceless tag at the root level of a child template in "%s" at line %d is deprecated since Twig 2.5.0 and will become a syntax error in 3.0.', $this->stream->getSourceContext()->getName(), $node->getTemplateLine()), \E_USER_DEPRECATED);
363          }
364   
365          // "block" tags that are not captured (see above) are only used for defining
366          // the content of the block. In such a case, nesting it does not work as
367          // expected as the definition is not part of the default template code flow.
368          if ($nested && ($node instanceof BlockReferenceNode || $node instanceof \Twig_Node_BlockReference)) {
369              //throw new SyntaxError('A block definition cannot be nested under non-capturing nodes.', $node->getTemplateLine(), $this->stream->getSourceContext());
370              @trigger_error(sprintf('Nesting a block definition under a non-capturing node in "%s" at line %d is deprecated since Twig 2.5.0 and will become a syntax error in 3.0.', $this->stream->getSourceContext()->getName(), $node->getTemplateLine()), \E_USER_DEPRECATED);
371   
372              return;
373          }
374   
375          // the "&& !$node instanceof SpacelessNode" part of the condition must be removed in 3.0
376          if ($node instanceof NodeOutputInterface && !$node instanceof SpacelessNode) {
377              return;
378          }
379   
380          // here, $nested means "being at the root level of a child template"
381          // we need to discard the wrapping "Twig_Node" for the "body" node
382          $nested = $nested || ('Twig_Node' !== \get_class($node) && Node::class !== \get_class($node));
383          foreach ($node as $k => $n) {
384              if (null !== $n && null === $this->filterBodyNodes($n, $nested)) {
385                  $node->removeNode($k);
386              }
387          }
388   
389          return $node;
390      }
391  }
392   
393  class_alias('Twig\Parser', 'Twig_Parser');
394