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