Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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

ExpressionParser.php

Zuletzt modifiziert: 09.10.2024, 12:57 - Dateigröße: 23.15 KiB


 001  <?php
 002   
 003  /*
 004   * This file is part of Twig.
 005   *
 006   * (c) 2009 Fabien Potencier
 007   * (c) 2009 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  /**
 014   * Parses expressions.
 015   *
 016   * This parser implements a "Precedence climbing" algorithm.
 017   *
 018   * @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
 019   * @see http://en.wikipedia.org/wiki/Operator-precedence_parser
 020   *
 021   * @author Fabien Potencier <fabien@symfony.com>
 022   */
 023  class Twig_ExpressionParser
 024  {
 025      const OPERATOR_LEFT = 1;
 026      const OPERATOR_RIGHT = 2;
 027   
 028      protected $parser;
 029      protected $unaryOperators;
 030      protected $binaryOperators;
 031   
 032      public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators)
 033      {
 034          $this->parser = $parser;
 035          $this->unaryOperators = $unaryOperators;
 036          $this->binaryOperators = $binaryOperators;
 037      }
 038   
 039      public function parseExpression($precedence = 0)
 040      {
 041          $expr = $this->getPrimary();
 042          $token = $this->parser->getCurrentToken();
 043          while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
 044              $op = $this->binaryOperators[$token->getValue()];
 045              $this->parser->getStream()->next();
 046   
 047              if (isset($op['callable'])) {
 048                  $expr = call_user_func($op['callable'], $this->parser, $expr);
 049              } else {
 050                  $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
 051                  $class = $op['class'];
 052                  $expr = new $class($expr, $expr1, $token->getLine());
 053              }
 054   
 055              $token = $this->parser->getCurrentToken();
 056          }
 057   
 058          if (0 === $precedence) {
 059              return $this->parseConditionalExpression($expr);
 060          }
 061   
 062          return $expr;
 063      }
 064   
 065      protected function getPrimary()
 066      {
 067          $token = $this->parser->getCurrentToken();
 068   
 069          if ($this->isUnary($token)) {
 070              $operator = $this->unaryOperators[$token->getValue()];
 071              $this->parser->getStream()->next();
 072              $expr = $this->parseExpression($operator['precedence']);
 073              $class = $operator['class'];
 074   
 075              return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
 076          } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
 077              $this->parser->getStream()->next();
 078              $expr = $this->parseExpression();
 079              $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
 080   
 081              return $this->parsePostfixExpression($expr);
 082          }
 083   
 084          return $this->parsePrimaryExpression();
 085      }
 086   
 087      protected function parseConditionalExpression($expr)
 088      {
 089          while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) {
 090              $this->parser->getStream()->next();
 091              if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
 092                  $expr2 = $this->parseExpression();
 093                  if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
 094                      $this->parser->getStream()->next();
 095                      $expr3 = $this->parseExpression();
 096                  } else {
 097                      $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
 098                  }
 099              } else {
 100                  $this->parser->getStream()->next();
 101                  $expr2 = $expr;
 102                  $expr3 = $this->parseExpression();
 103              }
 104   
 105              $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
 106          }
 107   
 108          return $expr;
 109      }
 110   
 111      protected function isUnary(Twig_Token $token)
 112      {
 113          return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
 114      }
 115   
 116      protected function isBinary(Twig_Token $token)
 117      {
 118          return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
 119      }
 120   
 121      public function parsePrimaryExpression()
 122      {
 123          $token = $this->parser->getCurrentToken();
 124          switch ($token->getType()) {
 125              case Twig_Token::NAME_TYPE:
 126                  $this->parser->getStream()->next();
 127                  switch ($token->getValue()) {
 128                      case 'true':
 129                      case 'TRUE':
 130                          $node = new Twig_Node_Expression_Constant(true, $token->getLine());
 131                          break;
 132   
 133                      case 'false':
 134                      case 'FALSE':
 135                          $node = new Twig_Node_Expression_Constant(false, $token->getLine());
 136                          break;
 137   
 138                      case 'none':
 139                      case 'NONE':
 140                      case 'null':
 141                      case 'NULL':
 142                          $node = new Twig_Node_Expression_Constant(null, $token->getLine());
 143                          break;
 144   
 145                      default:
 146                          if ('(' === $this->parser->getCurrentToken()->getValue()) {
 147                              $node = $this->getFunctionNode($token->getValue(), $token->getLine());
 148                          } else {
 149                              $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
 150                          }
 151                  }
 152                  break;
 153   
 154              case Twig_Token::NUMBER_TYPE:
 155                  $this->parser->getStream()->next();
 156                  $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
 157                  break;
 158   
 159              case Twig_Token::STRING_TYPE:
 160              case Twig_Token::INTERPOLATION_START_TYPE:
 161                  $node = $this->parseStringExpression();
 162                  break;
 163   
 164              default:
 165                  if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
 166                      $node = $this->parseArrayExpression();
 167                  } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
 168                      $node = $this->parseHashExpression();
 169                  } else {
 170                      throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
 171                  }
 172          }
 173   
 174          return $this->parsePostfixExpression($node);
 175      }
 176   
 177      public function parseStringExpression()
 178      {
 179          $stream = $this->parser->getStream();
 180   
 181          $nodes = array();
 182          // a string cannot be followed by another string in a single expression
 183          $nextCanBeString = true;
 184          while (true) {
 185              if ($stream->test(Twig_Token::STRING_TYPE) && $nextCanBeString) {
 186                  $token = $stream->next();
 187                  $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
 188                  $nextCanBeString = false;
 189              } elseif ($stream->test(Twig_Token::INTERPOLATION_START_TYPE)) {
 190                  $stream->next();
 191                  $nodes[] = $this->parseExpression();
 192                  $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
 193                  $nextCanBeString = true;
 194              } else {
 195                  break;
 196              }
 197          }
 198   
 199          $expr = array_shift($nodes);
 200          foreach ($nodes as $node) {
 201              $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine());
 202          }
 203   
 204          return $expr;
 205      }
 206   
 207      public function parseArrayExpression()
 208      {
 209          $stream = $this->parser->getStream();
 210          $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
 211   
 212          $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
 213          $first = true;
 214          while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
 215              if (!$first) {
 216                  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
 217   
 218                  // trailing ,?
 219                  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
 220                      break;
 221                  }
 222              }
 223              $first = false;
 224   
 225              $node->addElement($this->parseExpression());
 226          }
 227          $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
 228   
 229          return $node;
 230      }
 231   
 232      public function parseHashExpression()
 233      {
 234          $stream = $this->parser->getStream();
 235          $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
 236   
 237          $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
 238          $first = true;
 239          while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
 240              if (!$first) {
 241                  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
 242   
 243                  // trailing ,?
 244                  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
 245                      break;
 246                  }
 247              }
 248              $first = false;
 249   
 250              // a hash key can be:
 251              //
 252              //  * a number -- 12
 253              //  * a string -- 'a'
 254              //  * a name, which is equivalent to a string -- a
 255              //  * an expression, which must be enclosed in parentheses -- (1 + 2)
 256              if ($stream->test(Twig_Token::STRING_TYPE) || $stream->test(Twig_Token::NAME_TYPE) || $stream->test(Twig_Token::NUMBER_TYPE)) {
 257                  $token = $stream->next();
 258                  $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
 259              } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
 260                  $key = $this->parseExpression();
 261              } else {
 262                  $current = $stream->getCurrent();
 263   
 264                  throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType(), $current->getLine()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
 265              }
 266   
 267              $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
 268              $value = $this->parseExpression();
 269   
 270              $node->addElement($value, $key);
 271          }
 272          $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
 273   
 274          return $node;
 275      }
 276   
 277      public function parsePostfixExpression($node)
 278      {
 279          while (true) {
 280              $token = $this->parser->getCurrentToken();
 281              if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
 282                  if ('.' == $token->getValue() || '[' == $token->getValue()) {
 283                      $node = $this->parseSubscriptExpression($node);
 284                  } elseif ('|' == $token->getValue()) {
 285                      $node = $this->parseFilterExpression($node);
 286                  } else {
 287                      break;
 288                  }
 289              } else {
 290                  break;
 291              }
 292          }
 293   
 294          return $node;
 295      }
 296   
 297      public function getFunctionNode($name, $line)
 298      {
 299          switch ($name) {
 300              case 'parent':
 301                  $args = $this->parseArguments();
 302                  if (!count($this->parser->getBlockStack())) {
 303                      throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
 304                  }
 305   
 306                  if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
 307                      throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
 308                  }
 309   
 310                  return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
 311              case 'block':
 312                  return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
 313              case 'attribute':
 314                  $args = $this->parseArguments();
 315                  if (count($args) < 2) {
 316                      throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
 317                  }
 318   
 319                  return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_TemplateInterface::ANY_CALL, $line);
 320              default:
 321                  if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
 322                      $arguments = new Twig_Node_Expression_Array(array(), $line);
 323                      foreach ($this->parseArguments() as $n) {
 324                          $arguments->addElement($n);
 325                      }
 326   
 327                      $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
 328                      $node->setAttribute('safe', true);
 329   
 330                      return $node;
 331                  }
 332   
 333                  $args = $this->parseArguments(true);
 334                  $class = $this->getFunctionNodeClass($name, $line);
 335   
 336                  return new $class($name, $args, $line);
 337          }
 338      }
 339   
 340      public function parseSubscriptExpression($node)
 341      {
 342          $stream = $this->parser->getStream();
 343          $token = $stream->next();
 344          $lineno = $token->getLine();
 345          $arguments = new Twig_Node_Expression_Array(array(), $lineno);
 346          $type = Twig_TemplateInterface::ANY_CALL;
 347          if ($token->getValue() == '.') {
 348              $token = $stream->next();
 349              if (
 350                  $token->getType() == Twig_Token::NAME_TYPE
 351                  ||
 352                  $token->getType() == Twig_Token::NUMBER_TYPE
 353                  ||
 354                  ($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
 355              ) {
 356                  $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
 357   
 358                  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
 359                      $type = Twig_TemplateInterface::METHOD_CALL;
 360                      foreach ($this->parseArguments() as $n) {
 361                          $arguments->addElement($n);
 362                      }
 363                  }
 364              } else {
 365                  throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
 366              }
 367   
 368              if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
 369                  if (!$arg instanceof Twig_Node_Expression_Constant) {
 370                      throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
 371                  }
 372   
 373                  $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
 374                  $node->setAttribute('safe', true);
 375   
 376                  return $node;
 377              }
 378          } else {
 379              $type = Twig_TemplateInterface::ARRAY_CALL;
 380   
 381              // slice?
 382              $slice = false;
 383              if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
 384                  $slice = true;
 385                  $arg = new Twig_Node_Expression_Constant(0, $token->getLine());
 386              } else {
 387                  $arg = $this->parseExpression();
 388              }
 389   
 390              if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
 391                  $slice = true;
 392                  $stream->next();
 393              }
 394   
 395              if ($slice) {
 396                  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
 397                      $length = new Twig_Node_Expression_Constant(null, $token->getLine());
 398                  } else {
 399                      $length = $this->parseExpression();
 400                  }
 401   
 402                  $class = $this->getFilterNodeClass('slice', $token->getLine());
 403                  $arguments = new Twig_Node(array($arg, $length));
 404                  $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
 405   
 406                  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
 407   
 408                  return $filter;
 409              }
 410   
 411              $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
 412          }
 413   
 414          return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
 415      }
 416   
 417      public function parseFilterExpression($node)
 418      {
 419          $this->parser->getStream()->next();
 420   
 421          return $this->parseFilterExpressionRaw($node);
 422      }
 423   
 424      public function parseFilterExpressionRaw($node, $tag = null)
 425      {
 426          while (true) {
 427              $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
 428   
 429              $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
 430              if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
 431                  $arguments = new Twig_Node();
 432              } else {
 433                  $arguments = $this->parseArguments(true);
 434              }
 435   
 436              $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
 437   
 438              $node = new $class($node, $name, $arguments, $token->getLine(), $tag);
 439   
 440              if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
 441                  break;
 442              }
 443   
 444              $this->parser->getStream()->next();
 445          }
 446   
 447          return $node;
 448      }
 449   
 450      /**
 451       * Parses arguments.
 452       *
 453       * @param Boolean $namedArguments Whether to allow named arguments or not
 454       * @param Boolean $definition     Whether we are parsing arguments for a function definition
 455       */
 456      public function parseArguments($namedArguments = false, $definition = false)
 457      {
 458          $args = array();
 459          $stream = $this->parser->getStream();
 460   
 461          $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
 462          while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
 463              if (!empty($args)) {
 464                  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
 465              }
 466   
 467              if ($definition) {
 468                  $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
 469                  $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
 470              } else {
 471                  $value = $this->parseExpression();
 472              }
 473   
 474              $name = null;
 475              if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) {
 476                  $token = $stream->next();
 477                  if (!$value instanceof Twig_Node_Expression_Name) {
 478                      throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename());
 479                  }
 480                  $name = $value->getAttribute('name');
 481   
 482                  if ($definition) {
 483                      $value = $this->parsePrimaryExpression();
 484   
 485                      if (!$this->checkConstantExpression($value)) {
 486                          throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename());
 487                      }
 488                  } else {
 489                      $value = $this->parseExpression();
 490                  }
 491              }
 492   
 493              if ($definition) {
 494                  if (null === $name) {
 495                      $name = $value->getAttribute('name');
 496                      $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
 497                  }
 498                  $args[$name] = $value;
 499              } else {
 500                  if (null === $name) {
 501                      $args[] = $value;
 502                  } else {
 503                      $args[$name] = $value;
 504                  }
 505              }
 506          }
 507          $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
 508   
 509          return new Twig_Node($args);
 510      }
 511   
 512      public function parseAssignmentExpression()
 513      {
 514          $targets = array();
 515          while (true) {
 516              $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
 517              if (in_array($token->getValue(), array('true', 'false', 'none'))) {
 518                  throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
 519              }
 520              $targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
 521   
 522              if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
 523                  break;
 524              }
 525              $this->parser->getStream()->next();
 526          }
 527   
 528          return new Twig_Node($targets);
 529      }
 530   
 531      public function parseMultitargetExpression()
 532      {
 533          $targets = array();
 534          while (true) {
 535              $targets[] = $this->parseExpression();
 536              if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
 537                  break;
 538              }
 539              $this->parser->getStream()->next();
 540          }
 541   
 542          return new Twig_Node($targets);
 543      }
 544   
 545      protected function getFunctionNodeClass($name, $line)
 546      {
 547          $env = $this->parser->getEnvironment();
 548   
 549          if (false === $function = $env->getFunction($name)) {
 550              $message = sprintf('The function "%s" does not exist', $name);
 551              if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
 552                  $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
 553              }
 554   
 555              throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
 556          }
 557   
 558          if ($function instanceof Twig_SimpleFunction) {
 559              return $function->getNodeClass();
 560          }
 561   
 562          return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
 563      }
 564   
 565      protected function getFilterNodeClass($name, $line)
 566      {
 567          $env = $this->parser->getEnvironment();
 568   
 569          if (false === $filter = $env->getFilter($name)) {
 570              $message = sprintf('The filter "%s" does not exist', $name);
 571              if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) {
 572                  $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
 573              }
 574   
 575              throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
 576          }
 577   
 578          if ($filter instanceof Twig_SimpleFilter) {
 579              return $filter->getNodeClass();
 580          }
 581   
 582          return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
 583      }
 584   
 585      // checks that the node only contains "constant" elements
 586      protected function checkConstantExpression(Twig_NodeInterface $node)
 587      {
 588          if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) {
 589              return false;
 590          }
 591   
 592          foreach ($node as $n) {
 593              if (!$this->checkConstantExpression($n)) {
 594                  return false;
 595              }
 596          }
 597   
 598          return true;
 599      }
 600  }
 601