[ Index ]

PHP Cross Reference of phpBB-3.2.8-deutsch

title

Body

[close]

/vendor/twig/twig/src/ -> Parser.php (source)

   1  <?php
   2  
   3  /*
   4   * This file is part of Twig.
   5   *
   6   * (c) Fabien Potencier
   7   * (c) Armin Ronacher
   8   *
   9   * For the full copyright and license information, please view the LICENSE
  10   * file that was distributed with this source code.
  11   */
  12  
  13  namespace Twig;
  14  
  15  use Twig\Error\SyntaxError;
  16  use Twig\Node\BlockNode;
  17  use Twig\Node\BlockReferenceNode;
  18  use Twig\Node\BodyNode;
  19  use Twig\Node\Expression\AbstractExpression;
  20  use Twig\Node\MacroNode;
  21  use Twig\Node\ModuleNode;
  22  use Twig\Node\Node;
  23  use Twig\Node\NodeCaptureInterface;
  24  use Twig\Node\NodeOutputInterface;
  25  use Twig\Node\PrintNode;
  26  use Twig\Node\TextNode;
  27  use Twig\NodeVisitor\NodeVisitorInterface;
  28  use Twig\TokenParser\TokenParserInterface;
  29  
  30  /**
  31   * Default parser implementation.
  32   *
  33   * @author Fabien Potencier <fabien@symfony.com>
  34   */
  35  class Parser implements \Twig_ParserInterface
  36  {
  37      protected $stack = [];
  38      protected $stream;
  39      protected $parent;
  40      protected $handlers;
  41      protected $visitors;
  42      protected $expressionParser;
  43      protected $blocks;
  44      protected $blockStack;
  45      protected $macros;
  46      protected $env;
  47      protected $reservedMacroNames;
  48      protected $importedSymbols;
  49      protected $traits;
  50      protected $embeddedTemplates = [];
  51      private $varNameSalt = 0;
  52  
  53      public function __construct(Environment $env)
  54      {
  55          $this->env = $env;
  56      }
  57  
  58      /**
  59       * @deprecated since 1.27 (to be removed in 2.0)
  60       */
  61      public function getEnvironment()
  62      {
  63          @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0.', E_USER_DEPRECATED);
  64  
  65          return $this->env;
  66      }
  67  
  68      public function getVarName()
  69      {
  70          return sprintf('__internal_%s', hash('sha256', __METHOD__.$this->stream->getSourceContext()->getCode().$this->varNameSalt++));
  71      }
  72  
  73      /**
  74       * @deprecated since 1.27 (to be removed in 2.0). Use $parser->getStream()->getSourceContext()->getPath() instead.
  75       */
  76      public function getFilename()
  77      {
  78          @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use $parser->getStream()->getSourceContext()->getPath() instead.', __METHOD__), E_USER_DEPRECATED);
  79  
  80          return $this->stream->getSourceContext()->getName();
  81      }
  82  
  83      public function parse(TokenStream $stream, $test = null, $dropNeedle = false)
  84      {
  85          // push all variables into the stack to keep the current state of the parser
  86          // using get_object_vars() instead of foreach would lead to https://bugs.php.net/71336
  87          // This hack can be removed when min version if PHP 7.0
  88          $vars = [];
  89          foreach ($this as $k => $v) {
  90              $vars[$k] = $v;
  91          }
  92  
  93          unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames']);
  94          $this->stack[] = $vars;
  95  
  96          // tag handlers
  97          if (null === $this->handlers) {
  98              $this->handlers = $this->env->getTokenParsers();
  99              $this->handlers->setParser($this);
 100          }
 101  
 102          // node visitors
 103          if (null === $this->visitors) {
 104              $this->visitors = $this->env->getNodeVisitors();
 105          }
 106  
 107          if (null === $this->expressionParser) {
 108              $this->expressionParser = new ExpressionParser($this, $this->env);
 109          }
 110  
 111          $this->stream = $stream;
 112          $this->parent = null;
 113          $this->blocks = [];
 114          $this->macros = [];
 115          $this->traits = [];
 116          $this->blockStack = [];
 117          $this->importedSymbols = [[]];
 118          $this->embeddedTemplates = [];
 119          $this->varNameSalt = 0;
 120  
 121          try {
 122              $body = $this->subparse($test, $dropNeedle);
 123  
 124              if (null !== $this->parent && null === $body = $this->filterBodyNodes($body)) {
 125                  $body = new Node();
 126              }
 127          } catch (SyntaxError $e) {
 128              if (!$e->getSourceContext()) {
 129                  $e->setSourceContext($this->stream->getSourceContext());
 130              }
 131  
 132              if (!$e->getTemplateLine()) {
 133                  $e->setTemplateLine($this->stream->getCurrent()->getLine());
 134              }
 135  
 136              throw $e;
 137          }
 138  
 139          $node = new ModuleNode(new BodyNode([$body]), $this->parent, new Node($this->blocks), new Node($this->macros), new Node($this->traits), $this->embeddedTemplates, $stream->getSourceContext());
 140  
 141          $traverser = new NodeTraverser($this->env, $this->visitors);
 142  
 143          $node = $traverser->traverse($node);
 144  
 145          // restore previous stack so previous parse() call can resume working
 146          foreach (array_pop($this->stack) as $key => $val) {
 147              $this->$key = $val;
 148          }
 149  
 150          return $node;
 151      }
 152  
 153      public function subparse($test, $dropNeedle = false)
 154      {
 155          $lineno = $this->getCurrentToken()->getLine();
 156          $rv = [];
 157          while (!$this->stream->isEOF()) {
 158              switch ($this->getCurrentToken()->getType()) {
 159                  case Token::TEXT_TYPE:
 160                      $token = $this->stream->next();
 161                      $rv[] = new TextNode($token->getValue(), $token->getLine());
 162                      break;
 163  
 164                  case Token::VAR_START_TYPE:
 165                      $token = $this->stream->next();
 166                      $expr = $this->expressionParser->parseExpression();
 167                      $this->stream->expect(Token::VAR_END_TYPE);
 168                      $rv[] = new PrintNode($expr, $token->getLine());
 169                      break;
 170  
 171                  case Token::BLOCK_START_TYPE:
 172                      $this->stream->next();
 173                      $token = $this->getCurrentToken();
 174  
 175                      if (Token::NAME_TYPE !== $token->getType()) {
 176                          throw new SyntaxError('A block must start with a tag name.', $token->getLine(), $this->stream->getSourceContext());
 177                      }
 178  
 179                      if (null !== $test && \call_user_func($test, $token)) {
 180                          if ($dropNeedle) {
 181                              $this->stream->next();
 182                          }
 183  
 184                          if (1 === \count($rv)) {
 185                              return $rv[0];
 186                          }
 187  
 188                          return new Node($rv, [], $lineno);
 189                      }
 190  
 191                      $subparser = $this->handlers->getTokenParser($token->getValue());
 192                      if (null === $subparser) {
 193                          if (null !== $test) {
 194                              $e = new SyntaxError(sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->stream->getSourceContext());
 195  
 196                              if (\is_array($test) && isset($test[0]) && $test[0] instanceof TokenParserInterface) {
 197                                  $e->appendMessage(sprintf(' (expecting closing tag for the "%s" tag defined near line %s).', $test[0]->getTag(), $lineno));
 198                              }
 199                          } else {
 200                              $e = new SyntaxError(sprintf('Unknown "%s" tag.', $token->getValue()), $token->getLine(), $this->stream->getSourceContext());
 201                              $e->addSuggestions($token->getValue(), array_keys($this->env->getTags()));
 202                          }
 203  
 204                          throw $e;
 205                      }
 206  
 207                      $this->stream->next();
 208  
 209                      $node = $subparser->parse($token);
 210                      if (null !== $node) {
 211                          $rv[] = $node;
 212                      }
 213                      break;
 214  
 215                  default:
 216                      throw new SyntaxError('Lexer or parser ended up in unsupported state.', $this->getCurrentToken()->getLine(), $this->stream->getSourceContext());
 217              }
 218          }
 219  
 220          if (1 === \count($rv)) {
 221              return $rv[0];
 222          }
 223  
 224          return new Node($rv, [], $lineno);
 225      }
 226  
 227      /**
 228       * @deprecated since 1.27 (to be removed in 2.0)
 229       */
 230      public function addHandler($name, $class)
 231      {
 232          @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0.', E_USER_DEPRECATED);
 233  
 234          $this->handlers[$name] = $class;
 235      }
 236  
 237      /**
 238       * @deprecated since 1.27 (to be removed in 2.0)
 239       */
 240      public function addNodeVisitor(NodeVisitorInterface $visitor)
 241      {
 242          @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0.', E_USER_DEPRECATED);
 243  
 244          $this->visitors[] = $visitor;
 245      }
 246  
 247      public function getBlockStack()
 248      {
 249          return $this->blockStack;
 250      }
 251  
 252      public function peekBlockStack()
 253      {
 254          return isset($this->blockStack[\count($this->blockStack) - 1]) ? $this->blockStack[\count($this->blockStack) - 1] : null;
 255      }
 256  
 257      public function popBlockStack()
 258      {
 259          array_pop($this->blockStack);
 260      }
 261  
 262      public function pushBlockStack($name)
 263      {
 264          $this->blockStack[] = $name;
 265      }
 266  
 267      public function hasBlock($name)
 268      {
 269          return isset($this->blocks[$name]);
 270      }
 271  
 272      public function getBlock($name)
 273      {
 274          return $this->blocks[$name];
 275      }
 276  
 277      public function setBlock($name, BlockNode $value)
 278      {
 279          $this->blocks[$name] = new BodyNode([$value], [], $value->getTemplateLine());
 280      }
 281  
 282      public function hasMacro($name)
 283      {
 284          return isset($this->macros[$name]);
 285      }
 286  
 287      public function setMacro($name, MacroNode $node)
 288      {
 289          if ($this->isReservedMacroName($name)) {
 290              throw new SyntaxError(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword.', $name), $node->getTemplateLine(), $this->stream->getSourceContext());
 291          }
 292  
 293          $this->macros[$name] = $node;
 294      }
 295  
 296      public function isReservedMacroName($name)
 297      {
 298          if (null === $this->reservedMacroNames) {
 299              $this->reservedMacroNames = [];
 300              $r = new \ReflectionClass($this->env->getBaseTemplateClass());
 301              foreach ($r->getMethods() as $method) {
 302                  $methodName = strtolower($method->getName());
 303  
 304                  if ('get' === substr($methodName, 0, 3) && isset($methodName[3])) {
 305                      $this->reservedMacroNames[] = substr($methodName, 3);
 306                  }
 307              }
 308          }
 309  
 310          return \in_array(strtolower($name), $this->reservedMacroNames);
 311      }
 312  
 313      public function addTrait($trait)
 314      {
 315          $this->traits[] = $trait;
 316      }
 317  
 318      public function hasTraits()
 319      {
 320          return \count($this->traits) > 0;
 321      }
 322  
 323      public function embedTemplate(ModuleNode $template)
 324      {
 325          $template->setIndex(mt_rand());
 326  
 327          $this->embeddedTemplates[] = $template;
 328      }
 329  
 330      public function addImportedSymbol($type, $alias, $name = null, AbstractExpression $node = null)
 331      {
 332          $this->importedSymbols[0][$type][$alias] = ['name' => $name, 'node' => $node];
 333      }
 334  
 335      public function getImportedSymbol($type, $alias)
 336      {
 337          if (null !== $this->peekBlockStack()) {
 338              foreach ($this->importedSymbols as $functions) {
 339                  if (isset($functions[$type][$alias])) {
 340                      if (\count($this->blockStack) > 1) {
 341                          return null;
 342                      }
 343  
 344                      return $functions[$type][$alias];
 345                  }
 346              }
 347          } else {
 348              return isset($this->importedSymbols[0][$type][$alias]) ? $this->importedSymbols[0][$type][$alias] : null;
 349          }
 350      }
 351  
 352      public function isMainScope()
 353      {
 354          return 1 === \count($this->importedSymbols);
 355      }
 356  
 357      public function pushLocalScope()
 358      {
 359          array_unshift($this->importedSymbols, []);
 360      }
 361  
 362      public function popLocalScope()
 363      {
 364          array_shift($this->importedSymbols);
 365      }
 366  
 367      /**
 368       * @return ExpressionParser
 369       */
 370      public function getExpressionParser()
 371      {
 372          return $this->expressionParser;
 373      }
 374  
 375      public function getParent()
 376      {
 377          return $this->parent;
 378      }
 379  
 380      public function setParent($parent)
 381      {
 382          $this->parent = $parent;
 383      }
 384  
 385      /**
 386       * @return TokenStream
 387       */
 388      public function getStream()
 389      {
 390          return $this->stream;
 391      }
 392  
 393      /**
 394       * @return Token
 395       */
 396      public function getCurrentToken()
 397      {
 398          return $this->stream->getCurrent();
 399      }
 400  
 401      protected function filterBodyNodes(\Twig_NodeInterface $node)
 402      {
 403          // check that the body does not contain non-empty output nodes
 404          if (
 405              ($node instanceof TextNode && !ctype_space($node->getAttribute('data')))
 406              ||
 407              (!$node instanceof TextNode && !$node instanceof BlockReferenceNode && $node instanceof NodeOutputInterface)
 408          ) {
 409              if (false !== strpos((string) $node, \chr(0xEF).\chr(0xBB).\chr(0xBF))) {
 410                  $t = substr($node->getAttribute('data'), 3);
 411                  if ('' === $t || ctype_space($t)) {
 412                      // bypass empty nodes starting with a BOM
 413                      return;
 414                  }
 415              }
 416  
 417              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());
 418          }
 419  
 420          // bypass nodes that will "capture" the output
 421          if ($node instanceof NodeCaptureInterface) {
 422              return $node;
 423          }
 424  
 425          if ($node instanceof NodeOutputInterface) {
 426              return;
 427          }
 428  
 429          foreach ($node as $k => $n) {
 430              if (null !== $n && null === $this->filterBodyNodes($n)) {
 431                  $node->removeNode($k);
 432              }
 433          }
 434  
 435          return $node;
 436      }
 437  }
 438  
 439  class_alias('Twig\Parser', 'Twig_Parser');


Generated: Tue Apr 7 19:42:26 2020 Cross-referenced by PHPXref 0.7.1