Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

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: 25.41 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()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) {
 090              if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
 091                  $expr2 = $this->parseExpression();
 092                  if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
 093                      $expr3 = $this->parseExpression();
 094                  } else {
 095                      $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
 096                  }
 097              } else {
 098                  $expr2 = $expr;
 099                  $expr3 = $this->parseExpression();
 100              }
 101   
 102              $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
 103          }
 104   
 105          return $expr;
 106      }
 107   
 108      protected function isUnary(Twig_Token $token)
 109      {
 110          return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
 111      }
 112   
 113      protected function isBinary(Twig_Token $token)
 114      {
 115          return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
 116      }
 117   
 118      public function parsePrimaryExpression()
 119      {
 120          $token = $this->parser->getCurrentToken();
 121          switch ($token->getType()) {
 122              case Twig_Token::NAME_TYPE:
 123                  $this->parser->getStream()->next();
 124                  switch ($token->getValue()) {
 125                      case 'true':
 126                      case 'TRUE':
 127                          $node = new Twig_Node_Expression_Constant(true, $token->getLine());
 128                          break;
 129   
 130                      case 'false':
 131                      case 'FALSE':
 132                          $node = new Twig_Node_Expression_Constant(false, $token->getLine());
 133                          break;
 134   
 135                      case 'none':
 136                      case 'NONE':
 137                      case 'null':
 138                      case 'NULL':
 139                          $node = new Twig_Node_Expression_Constant(null, $token->getLine());
 140                          break;
 141   
 142                      default:
 143                          if ('(' === $this->parser->getCurrentToken()->getValue()) {
 144                              $node = $this->getFunctionNode($token->getValue(), $token->getLine());
 145                          } else {
 146                              $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
 147                          }
 148                  }
 149                  break;
 150   
 151              case Twig_Token::NUMBER_TYPE:
 152                  $this->parser->getStream()->next();
 153                  $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
 154                  break;
 155   
 156              case Twig_Token::STRING_TYPE:
 157              case Twig_Token::INTERPOLATION_START_TYPE:
 158                  $node = $this->parseStringExpression();
 159                  break;
 160   
 161              case Twig_Token::OPERATOR_TYPE:
 162                  if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
 163                      // in this context, string operators are variable names
 164                      $this->parser->getStream()->next();
 165                      $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
 166                      break;
 167                  } elseif (isset($this->unaryOperators[$token->getValue()])) {
 168                      $class = $this->unaryOperators[$token->getValue()]['class'];
 169   
 170                      $ref = new ReflectionClass($class);
 171                      $negClass = 'Twig_Node_Expression_Unary_Neg';
 172                      $posClass = 'Twig_Node_Expression_Unary_Pos';
 173                      if (!(in_array($ref->getName(), array($negClass, $posClass)) || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass))) {
 174                          throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getFilename());
 175                      }
 176   
 177                      $this->parser->getStream()->next();
 178                      $expr = $this->parsePrimaryExpression();
 179   
 180                      $node = new $class($expr, $token->getLine());
 181                      break;
 182                  }
 183   
 184              default:
 185                  if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
 186                      $node = $this->parseArrayExpression();
 187                  } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
 188                      $node = $this->parseHashExpression();
 189                  } else {
 190                      throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
 191                  }
 192          }
 193   
 194          return $this->parsePostfixExpression($node);
 195      }
 196   
 197      public function parseStringExpression()
 198      {
 199          $stream = $this->parser->getStream();
 200   
 201          $nodes = array();
 202          // a string cannot be followed by another string in a single expression
 203          $nextCanBeString = true;
 204          while (true) {
 205              if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) {
 206                  $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
 207                  $nextCanBeString = false;
 208              } elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) {
 209                  $nodes[] = $this->parseExpression();
 210                  $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
 211                  $nextCanBeString = true;
 212              } else {
 213                  break;
 214              }
 215          }
 216   
 217          $expr = array_shift($nodes);
 218          foreach ($nodes as $node) {
 219              $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine());
 220          }
 221   
 222          return $expr;
 223      }
 224   
 225      public function parseArrayExpression()
 226      {
 227          $stream = $this->parser->getStream();
 228          $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
 229   
 230          $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
 231          $first = true;
 232          while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
 233              if (!$first) {
 234                  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
 235   
 236                  // trailing ,?
 237                  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
 238                      break;
 239                  }
 240              }
 241              $first = false;
 242   
 243              $node->addElement($this->parseExpression());
 244          }
 245          $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
 246   
 247          return $node;
 248      }
 249   
 250      public function parseHashExpression()
 251      {
 252          $stream = $this->parser->getStream();
 253          $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
 254   
 255          $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
 256          $first = true;
 257          while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
 258              if (!$first) {
 259                  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
 260   
 261                  // trailing ,?
 262                  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
 263                      break;
 264                  }
 265              }
 266              $first = false;
 267   
 268              // a hash key can be:
 269              //
 270              //  * a number -- 12
 271              //  * a string -- 'a'
 272              //  * a name, which is equivalent to a string -- a
 273              //  * an expression, which must be enclosed in parentheses -- (1 + 2)
 274              if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) {
 275                  $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
 276              } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
 277                  $key = $this->parseExpression();
 278              } else {
 279                  $current = $stream->getCurrent();
 280   
 281                  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->getValue()), $current->getLine(), $this->parser->getFilename());
 282              }
 283   
 284              $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
 285              $value = $this->parseExpression();
 286   
 287              $node->addElement($value, $key);
 288          }
 289          $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
 290   
 291          return $node;
 292      }
 293   
 294      public function parsePostfixExpression($node)
 295      {
 296          while (true) {
 297              $token = $this->parser->getCurrentToken();
 298              if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
 299                  if ('.' == $token->getValue() || '[' == $token->getValue()) {
 300                      $node = $this->parseSubscriptExpression($node);
 301                  } elseif ('|' == $token->getValue()) {
 302                      $node = $this->parseFilterExpression($node);
 303                  } else {
 304                      break;
 305                  }
 306              } else {
 307                  break;
 308              }
 309          }
 310   
 311          return $node;
 312      }
 313   
 314      public function getFunctionNode($name, $line)
 315      {
 316          switch ($name) {
 317              case 'parent':
 318                  $this->parseArguments();
 319                  if (!count($this->parser->getBlockStack())) {
 320                      throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden.', $line, $this->parser->getFilename());
 321                  }
 322   
 323                  if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
 324                      throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getFilename());
 325                  }
 326   
 327                  return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
 328              case 'block':
 329                  return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
 330              case 'attribute':
 331                  $args = $this->parseArguments();
 332                  if (count($args) < 2) {
 333                      throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getFilename());
 334                  }
 335   
 336                  return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line);
 337              default:
 338                  if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
 339                      $arguments = new Twig_Node_Expression_Array(array(), $line);
 340                      foreach ($this->parseArguments() as $n) {
 341                          $arguments->addElement($n);
 342                      }
 343   
 344                      $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
 345                      $node->setAttribute('safe', true);
 346   
 347                      return $node;
 348                  }
 349   
 350                  $args = $this->parseArguments(true);
 351                  $class = $this->getFunctionNodeClass($name, $line);
 352   
 353                  return new $class($name, $args, $line);
 354          }
 355      }
 356   
 357      public function parseSubscriptExpression($node)
 358      {
 359          $stream = $this->parser->getStream();
 360          $token = $stream->next();
 361          $lineno = $token->getLine();
 362          $arguments = new Twig_Node_Expression_Array(array(), $lineno);
 363          $type = Twig_Template::ANY_CALL;
 364          if ($token->getValue() == '.') {
 365              $token = $stream->next();
 366              if (
 367                  $token->getType() == Twig_Token::NAME_TYPE
 368                  ||
 369                  $token->getType() == Twig_Token::NUMBER_TYPE
 370                  ||
 371                  ($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
 372              ) {
 373                  $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
 374   
 375                  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
 376                      $type = Twig_Template::METHOD_CALL;
 377                      foreach ($this->parseArguments() as $n) {
 378                          $arguments->addElement($n);
 379                      }
 380                  }
 381              } else {
 382                  throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
 383              }
 384   
 385              if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
 386                  if (!$arg instanceof Twig_Node_Expression_Constant) {
 387                      throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
 388                  }
 389   
 390                  $name = $arg->getAttribute('value');
 391   
 392                  if ($this->parser->isReservedMacroName($name)) {
 393                      throw new Twig_Error_Syntax(sprintf('"%s" cannot be called as macro as it is a reserved keyword.', $name), $token->getLine(), $this->parser->getFilename());
 394                  }
 395   
 396                  $node = new Twig_Node_Expression_MethodCall($node, 'get'.$name, $arguments, $lineno);
 397                  $node->setAttribute('safe', true);
 398   
 399                  return $node;
 400              }
 401          } else {
 402              $type = Twig_Template::ARRAY_CALL;
 403   
 404              // slice?
 405              $slice = false;
 406              if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
 407                  $slice = true;
 408                  $arg = new Twig_Node_Expression_Constant(0, $token->getLine());
 409              } else {
 410                  $arg = $this->parseExpression();
 411              }
 412   
 413              if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
 414                  $slice = true;
 415              }
 416   
 417              if ($slice) {
 418                  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
 419                      $length = new Twig_Node_Expression_Constant(null, $token->getLine());
 420                  } else {
 421                      $length = $this->parseExpression();
 422                  }
 423   
 424                  $class = $this->getFilterNodeClass('slice', $token->getLine());
 425                  $arguments = new Twig_Node(array($arg, $length));
 426                  $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
 427   
 428                  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
 429   
 430                  return $filter;
 431              }
 432   
 433              $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
 434          }
 435   
 436          return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
 437      }
 438   
 439      public function parseFilterExpression($node)
 440      {
 441          $this->parser->getStream()->next();
 442   
 443          return $this->parseFilterExpressionRaw($node);
 444      }
 445   
 446      public function parseFilterExpressionRaw($node, $tag = null)
 447      {
 448          while (true) {
 449              $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
 450   
 451              $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
 452              if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
 453                  $arguments = new Twig_Node();
 454              } else {
 455                  $arguments = $this->parseArguments(true);
 456              }
 457   
 458              $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
 459   
 460              $node = new $class($node, $name, $arguments, $token->getLine(), $tag);
 461   
 462              if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
 463                  break;
 464              }
 465   
 466              $this->parser->getStream()->next();
 467          }
 468   
 469          return $node;
 470      }
 471   
 472      /**
 473       * Parses arguments.
 474       *
 475       * @param bool $namedArguments Whether to allow named arguments or not
 476       * @param bool $definition     Whether we are parsing arguments for a function definition
 477       *
 478       * @return Twig_Node
 479       *
 480       * @throws Twig_Error_Syntax
 481       */
 482      public function parseArguments($namedArguments = false, $definition = false)
 483      {
 484          $args = array();
 485          $stream = $this->parser->getStream();
 486   
 487          $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
 488          while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
 489              if (!empty($args)) {
 490                  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
 491              }
 492   
 493              if ($definition) {
 494                  $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
 495                  $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
 496              } else {
 497                  $value = $this->parseExpression();
 498              }
 499   
 500              $name = null;
 501              if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
 502                  if (!$value instanceof Twig_Node_Expression_Name) {
 503                      throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given.', get_class($value)), $token->getLine(), $this->parser->getFilename());
 504                  }
 505                  $name = $value->getAttribute('name');
 506   
 507                  if ($definition) {
 508                      $value = $this->parsePrimaryExpression();
 509   
 510                      if (!$this->checkConstantExpression($value)) {
 511                          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());
 512                      }
 513                  } else {
 514                      $value = $this->parseExpression();
 515                  }
 516              }
 517   
 518              if ($definition) {
 519                  if (null === $name) {
 520                      $name = $value->getAttribute('name');
 521                      $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
 522                  }
 523                  $args[$name] = $value;
 524              } else {
 525                  if (null === $name) {
 526                      $args[] = $value;
 527                  } else {
 528                      $args[$name] = $value;
 529                  }
 530              }
 531          }
 532          $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
 533   
 534          return new Twig_Node($args);
 535      }
 536   
 537      public function parseAssignmentExpression()
 538      {
 539          $targets = array();
 540          while (true) {
 541              $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
 542              $value = $token->getValue();
 543              if (in_array(strtolower($value), array('true', 'false', 'none', 'null'))) {
 544                  throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $value), $token->getLine(), $this->parser->getFilename());
 545              }
 546              $targets[] = new Twig_Node_Expression_AssignName($value, $token->getLine());
 547   
 548              if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
 549                  break;
 550              }
 551          }
 552   
 553          return new Twig_Node($targets);
 554      }
 555   
 556      public function parseMultitargetExpression()
 557      {
 558          $targets = array();
 559          while (true) {
 560              $targets[] = $this->parseExpression();
 561              if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
 562                  break;
 563              }
 564          }
 565   
 566          return new Twig_Node($targets);
 567      }
 568   
 569      protected function getFunctionNodeClass($name, $line)
 570      {
 571          $env = $this->parser->getEnvironment();
 572   
 573          if (false === $function = $env->getFunction($name)) {
 574              $e = new Twig_Error_Syntax(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getFilename());
 575              $e->addSuggestions($name, array_keys($env->getFunctions()));
 576   
 577              throw $e;
 578          }
 579   
 580          if ($function instanceof Twig_SimpleFunction && $function->isDeprecated()) {
 581              $message = sprintf('Twig Function "%s" is deprecated', $function->getName());
 582              if (!is_bool($function->getDeprecatedVersion())) {
 583                  $message .= sprintf(' since version %s', $function->getDeprecatedVersion());
 584              }
 585              if ($function->getAlternative()) {
 586                  $message .= sprintf('. Use "%s" instead', $function->getAlternative());
 587              }
 588              $message .= sprintf(' in %s at line %d.', $this->parser->getFilename(), $line);
 589   
 590              @trigger_error($message, E_USER_DEPRECATED);
 591          }
 592   
 593          if ($function instanceof Twig_SimpleFunction) {
 594              return $function->getNodeClass();
 595          }
 596   
 597          return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
 598      }
 599   
 600      protected function getFilterNodeClass($name, $line)
 601      {
 602          $env = $this->parser->getEnvironment();
 603   
 604          if (false === $filter = $env->getFilter($name)) {
 605              $e = new Twig_Error_Syntax(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getFilename());
 606              $e->addSuggestions($name, array_keys($env->getFilters()));
 607   
 608              throw $e;
 609          }
 610   
 611          if ($filter instanceof Twig_SimpleFilter && $filter->isDeprecated()) {
 612              $message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
 613              if (!is_bool($filter->getDeprecatedVersion())) {
 614                  $message .= sprintf(' since version %s', $filter->getDeprecatedVersion());
 615              }
 616              if ($filter->getAlternative()) {
 617                  $message .= sprintf('. Use "%s" instead', $filter->getAlternative());
 618              }
 619              $message .= sprintf(' in %s at line %d.', $this->parser->getFilename(), $line);
 620   
 621              @trigger_error($message, E_USER_DEPRECATED);
 622          }
 623   
 624          if ($filter instanceof Twig_SimpleFilter) {
 625              return $filter->getNodeClass();
 626          }
 627   
 628          return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
 629      }
 630   
 631      // checks that the node only contains "constant" elements
 632      protected function checkConstantExpression(Twig_NodeInterface $node)
 633      {
 634          if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array
 635              || $node instanceof Twig_Node_Expression_Unary_Neg || $node instanceof Twig_Node_Expression_Unary_Pos
 636          )) {
 637              return false;
 638          }
 639   
 640          foreach ($node as $n) {
 641              if (!$this->checkConstantExpression($n)) {
 642                  return false;
 643              }
 644          }
 645   
 646          return true;
 647      }
 648  }
 649