ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
ExpressionParser.php
Go to the documentation of this file.
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 
26 {
27  const OPERATOR_LEFT = 1;
28  const OPERATOR_RIGHT = 2;
29 
30  protected $parser;
31  protected $unaryOperators;
32  protected $binaryOperators;
33 
34  private $env;
35 
36  public function __construct(Twig_Parser $parser, $env = null)
37  {
38  $this->parser = $parser;
39 
40  if ($env instanceof Twig_Environment) {
41  $this->env = $env;
42  $this->unaryOperators = $env->getUnaryOperators();
43  $this->binaryOperators = $env->getBinaryOperators();
44  } else {
45  @trigger_error('Passing the operators as constructor arguments to '.__METHOD__.' is deprecated since version 1.27. Pass the environment instead.', E_USER_DEPRECATED);
46 
47  $this->env = $parser->getEnvironment();
48  $this->unaryOperators = func_get_arg(1);
49  $this->binaryOperators = func_get_arg(2);
50  }
51  }
52 
53  public function parseExpression($precedence = 0)
54  {
55  $expr = $this->getPrimary();
56  $token = $this->parser->getCurrentToken();
57  while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
58  $op = $this->binaryOperators[$token->getValue()];
59  $this->parser->getStream()->next();
60 
61  if ('is not' === $token->getValue()) {
62  $expr = $this->parseNotTestExpression($expr);
63  } elseif ('is' === $token->getValue()) {
64  $expr = $this->parseTestExpression($expr);
65  } elseif (isset($op['callable'])) {
66  $expr = call_user_func($op['callable'], $this->parser, $expr);
67  } else {
68  $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
69  $class = $op['class'];
70  $expr = new $class($expr, $expr1, $token->getLine());
71  }
72 
73  $token = $this->parser->getCurrentToken();
74  }
75 
76  if (0 === $precedence) {
77  return $this->parseConditionalExpression($expr);
78  }
79 
80  return $expr;
81  }
82 
83  protected function getPrimary()
84  {
85  $token = $this->parser->getCurrentToken();
86 
87  if ($this->isUnary($token)) {
88  $operator = $this->unaryOperators[$token->getValue()];
89  $this->parser->getStream()->next();
90  $expr = $this->parseExpression($operator['precedence']);
91  $class = $operator['class'];
92 
93  return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
94  } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
95  $this->parser->getStream()->next();
96  $expr = $this->parseExpression();
97  $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
98 
99  return $this->parsePostfixExpression($expr);
100  }
101 
102  return $this->parsePrimaryExpression();
103  }
104 
105  protected function parseConditionalExpression($expr)
106  {
107  while ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) {
108  if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
109  $expr2 = $this->parseExpression();
110  if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
111  $expr3 = $this->parseExpression();
112  } else {
113  $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
114  }
115  } else {
116  $expr2 = $expr;
117  $expr3 = $this->parseExpression();
118  }
119 
120  $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
121  }
122 
123  return $expr;
124  }
125 
126  protected function isUnary(Twig_Token $token)
127  {
128  return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
129  }
130 
131  protected function isBinary(Twig_Token $token)
132  {
133  return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
134  }
135 
136  public function parsePrimaryExpression()
137  {
138  $token = $this->parser->getCurrentToken();
139  switch ($token->getType()) {
141  $this->parser->getStream()->next();
142  switch ($token->getValue()) {
143  case 'true':
144  case 'TRUE':
145  $node = new Twig_Node_Expression_Constant(true, $token->getLine());
146  break;
147 
148  case 'false':
149  case 'FALSE':
150  $node = new Twig_Node_Expression_Constant(false, $token->getLine());
151  break;
152 
153  case 'none':
154  case 'NONE':
155  case 'null':
156  case 'NULL':
157  $node = new Twig_Node_Expression_Constant(null, $token->getLine());
158  break;
159 
160  default:
161  if ('(' === $this->parser->getCurrentToken()->getValue()) {
162  $node = $this->getFunctionNode($token->getValue(), $token->getLine());
163  } else {
164  $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
165  }
166  }
167  break;
168 
170  $this->parser->getStream()->next();
171  $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
172  break;
173 
176  $node = $this->parseStringExpression();
177  break;
178 
180  if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) {
181  // in this context, string operators are variable names
182  $this->parser->getStream()->next();
183  $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
184  break;
185  } elseif (isset($this->unaryOperators[$token->getValue()])) {
186  $class = $this->unaryOperators[$token->getValue()]['class'];
187 
188  $ref = new ReflectionClass($class);
189  $negClass = 'Twig_Node_Expression_Unary_Neg';
190  $posClass = 'Twig_Node_Expression_Unary_Pos';
191  if (!(in_array($ref->getName(), array($negClass, $posClass)) || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass))) {
192  throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
193  }
194 
195  $this->parser->getStream()->next();
196  $expr = $this->parsePrimaryExpression();
197 
198  $node = new $class($expr, $token->getLine());
199  break;
200  }
201 
202  // no break
203  default:
204  if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
205  $node = $this->parseArrayExpression();
206  } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
207  $node = $this->parseHashExpression();
208  } elseif ($token->test(Twig_Token::OPERATOR_TYPE, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) {
209  throw new Twig_Error_Syntax(sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
210  } else {
211  throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext());
212  }
213  }
214 
215  return $this->parsePostfixExpression($node);
216  }
217 
218  public function parseStringExpression()
219  {
220  $stream = $this->parser->getStream();
221 
222  $nodes = array();
223  // a string cannot be followed by another string in a single expression
224  $nextCanBeString = true;
225  while (true) {
226  if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) {
227  $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
228  $nextCanBeString = false;
229  } elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) {
230  $nodes[] = $this->parseExpression();
232  $nextCanBeString = true;
233  } else {
234  break;
235  }
236  }
237 
238  $expr = array_shift($nodes);
239  foreach ($nodes as $node) {
240  $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getTemplateLine());
241  }
242 
243  return $expr;
244  }
245 
246  public function parseArrayExpression()
247  {
248  $stream = $this->parser->getStream();
249  $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
250 
251  $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
252  $first = true;
253  while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
254  if (!$first) {
255  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
256 
257  // trailing ,?
258  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
259  break;
260  }
261  }
262  $first = false;
263 
264  $node->addElement($this->parseExpression());
265  }
266  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
267 
268  return $node;
269  }
270 
271  public function parseHashExpression()
272  {
273  $stream = $this->parser->getStream();
274  $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
275 
276  $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
277  $first = true;
278  while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
279  if (!$first) {
280  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
281 
282  // trailing ,?
283  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
284  break;
285  }
286  }
287  $first = false;
288 
289  // a hash key can be:
290  //
291  // * a number -- 12
292  // * a string -- 'a'
293  // * a name, which is equivalent to a string -- a
294  // * an expression, which must be enclosed in parentheses -- (1 + 2)
295  if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) {
296  $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
297  } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
298  $key = $this->parseExpression();
299  } else {
300  $current = $stream->getCurrent();
301 
302  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(), $stream->getSourceContext());
303  }
304 
305  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
306  $value = $this->parseExpression();
307 
308  $node->addElement($value, $key);
309  }
310  $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
311 
312  return $node;
313  }
314 
315  public function parsePostfixExpression($node)
316  {
317  while (true) {
318  $token = $this->parser->getCurrentToken();
319  if (Twig_Token::PUNCTUATION_TYPE == $token->getType()) {
320  if ('.' == $token->getValue() || '[' == $token->getValue()) {
321  $node = $this->parseSubscriptExpression($node);
322  } elseif ('|' == $token->getValue()) {
323  $node = $this->parseFilterExpression($node);
324  } else {
325  break;
326  }
327  } else {
328  break;
329  }
330  }
331 
332  return $node;
333  }
334 
335  public function getFunctionNode($name, $line)
336  {
337  switch ($name) {
338  case 'parent':
339  $this->parseArguments();
340  if (!count($this->parser->getBlockStack())) {
341  throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext());
342  }
343 
344  if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
345  throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext());
346  }
347 
348  return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
349  case 'block':
350  $args = $this->parseArguments();
351  if (count($args) < 1) {
352  throw new Twig_Error_Syntax('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext());
353  }
354 
355  return new Twig_Node_Expression_BlockReference($args->getNode(0), count($args) > 1 ? $args->getNode(1) : null, $line);
356  case 'attribute':
357  $args = $this->parseArguments();
358  if (count($args) < 2) {
359  throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext());
360  }
361 
362  return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line);
363  default:
364  if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
365  $arguments = new Twig_Node_Expression_Array(array(), $line);
366  foreach ($this->parseArguments() as $n) {
367  $arguments->addElement($n);
368  }
369 
370  $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
371  $node->setAttribute('safe', true);
372 
373  return $node;
374  }
375 
376  $args = $this->parseArguments(true);
377  $class = $this->getFunctionNodeClass($name, $line);
378 
379  return new $class($name, $args, $line);
380  }
381  }
382 
383  public function parseSubscriptExpression($node)
384  {
385  $stream = $this->parser->getStream();
386  $token = $stream->next();
387  $lineno = $token->getLine();
388  $arguments = new Twig_Node_Expression_Array(array(), $lineno);
390  if ('.' == $token->getValue()) {
391  $token = $stream->next();
392  if (
393  Twig_Token::NAME_TYPE == $token->getType()
394  ||
395  Twig_Token::NUMBER_TYPE == $token->getType()
396  ||
397  (Twig_Token::OPERATOR_TYPE == $token->getType() && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
398  ) {
399  $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
400 
401  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
403  foreach ($this->parseArguments() as $n) {
404  $arguments->addElement($n);
405  }
406  }
407  } else {
408  throw new Twig_Error_Syntax('Expected name or number.', $lineno, $stream->getSourceContext());
409  }
410 
411  if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
412  if (!$arg instanceof Twig_Node_Expression_Constant) {
413  throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext());
414  }
415 
416  $name = $arg->getAttribute('value');
417 
418  if ($this->parser->isReservedMacroName($name)) {
419  throw new Twig_Error_Syntax(sprintf('"%s" cannot be called as macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext());
420  }
421 
422  $node = new Twig_Node_Expression_MethodCall($node, 'get'.$name, $arguments, $lineno);
423  $node->setAttribute('safe', true);
424 
425  return $node;
426  }
427  } else {
429 
430  // slice?
431  $slice = false;
432  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
433  $slice = true;
434  $arg = new Twig_Node_Expression_Constant(0, $token->getLine());
435  } else {
436  $arg = $this->parseExpression();
437  }
438 
439  if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
440  $slice = true;
441  }
442 
443  if ($slice) {
444  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
445  $length = new Twig_Node_Expression_Constant(null, $token->getLine());
446  } else {
447  $length = $this->parseExpression();
448  }
449 
450  $class = $this->getFilterNodeClass('slice', $token->getLine());
451  $arguments = new Twig_Node(array($arg, $length));
452  $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
453 
455 
456  return $filter;
457  }
458 
460  }
461 
462  return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
463  }
464 
465  public function parseFilterExpression($node)
466  {
467  $this->parser->getStream()->next();
468 
469  return $this->parseFilterExpressionRaw($node);
470  }
471 
472  public function parseFilterExpressionRaw($node, $tag = null)
473  {
474  while (true) {
475  $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
476 
477  $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
478  if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
479  $arguments = new Twig_Node();
480  } else {
481  $arguments = $this->parseArguments(true);
482  }
483 
484  $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
485 
486  $node = new $class($node, $name, $arguments, $token->getLine(), $tag);
487 
488  if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
489  break;
490  }
491 
492  $this->parser->getStream()->next();
493  }
494 
495  return $node;
496  }
497 
508  public function parseArguments($namedArguments = false, $definition = false)
509  {
510  $args = array();
511  $stream = $this->parser->getStream();
512 
513  $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
514  while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
515  if (!empty($args)) {
516  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
517  }
518 
519  if ($definition) {
520  $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
521  $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
522  } else {
523  $value = $this->parseExpression();
524  }
525 
526  $name = null;
527  if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
528  if (!$value instanceof Twig_Node_Expression_Name) {
529  throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given.', get_class($value)), $token->getLine(), $stream->getSourceContext());
530  }
531  $name = $value->getAttribute('name');
532 
533  if ($definition) {
534  $value = $this->parsePrimaryExpression();
535 
536  if (!$this->checkConstantExpression($value)) {
537  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(), $stream->getSourceContext());
538  }
539  } else {
540  $value = $this->parseExpression();
541  }
542  }
543 
544  if ($definition) {
545  if (null === $name) {
546  $name = $value->getAttribute('name');
547  $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
548  }
549  $args[$name] = $value;
550  } else {
551  if (null === $name) {
552  $args[] = $value;
553  } else {
554  $args[$name] = $value;
555  }
556  }
557  }
558  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
559 
560  return new Twig_Node($args);
561  }
562 
563  public function parseAssignmentExpression()
564  {
565  $stream = $this->parser->getStream();
566  $targets = array();
567  while (true) {
568  $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
569  $value = $token->getValue();
570  if (in_array(strtolower($value), array('true', 'false', 'none', 'null'))) {
571  throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
572  }
573  $targets[] = new Twig_Node_Expression_AssignName($value, $token->getLine());
574 
575  if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
576  break;
577  }
578  }
579 
580  return new Twig_Node($targets);
581  }
582 
583  public function parseMultitargetExpression()
584  {
585  $targets = array();
586  while (true) {
587  $targets[] = $this->parseExpression();
588  if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
589  break;
590  }
591  }
592 
593  return new Twig_Node($targets);
594  }
595 
597  {
598  return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine());
599  }
600 
601  private function parseTestExpression(Twig_NodeInterface $node)
602  {
603  $stream = $this->parser->getStream();
604  list($name, $test) = $this->getTest($node->getTemplateLine());
605 
606  $class = $this->getTestNodeClass($test);
607  $arguments = null;
608  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
609  $arguments = $this->parser->getExpressionParser()->parseArguments(true);
610  }
611 
612  return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine());
613  }
614 
615  private function getTest($line)
616  {
617  $stream = $this->parser->getStream();
618  $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
619 
620  if ($test = $this->env->getTest($name)) {
621  return array($name, $test);
622  }
623 
624  if ($stream->test(Twig_Token::NAME_TYPE)) {
625  // try 2-words tests
626  $name = $name.' '.$this->parser->getCurrentToken()->getValue();
627 
628  if ($test = $this->env->getTest($name)) {
629  $stream->next();
630 
631  return array($name, $test);
632  }
633  }
634 
635  $e = new Twig_Error_Syntax(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
636  $e->addSuggestions($name, array_keys($this->env->getTests()));
637 
638  throw $e;
639  }
640 
641  private function getTestNodeClass($test)
642  {
643  if ($test instanceof Twig_SimpleTest && $test->isDeprecated()) {
644  $stream = $this->parser->getStream();
645  $message = sprintf('Twig Test "%s" is deprecated', $test->getName());
646  if (!is_bool($test->getDeprecatedVersion())) {
647  $message .= sprintf(' since version %s', $test->getDeprecatedVersion());
648  }
649  if ($test->getAlternative()) {
650  $message .= sprintf('. Use "%s" instead', $test->getAlternative());
651  }
652  $src = $stream->getSourceContext();
653  $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $stream->getCurrent()->getLine());
654 
655  @trigger_error($message, E_USER_DEPRECATED);
656  }
657 
658  if ($test instanceof Twig_SimpleTest) {
659  return $test->getNodeClass();
660  }
661 
662  return $test instanceof Twig_Test_Node ? $test->getClass() : 'Twig_Node_Expression_Test';
663  }
664 
665  protected function getFunctionNodeClass($name, $line)
666  {
667  if (false === $function = $this->env->getFunction($name)) {
668  $e = new Twig_Error_Syntax(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
669  $e->addSuggestions($name, array_keys($this->env->getFunctions()));
670 
671  throw $e;
672  }
673 
674  if ($function instanceof Twig_SimpleFunction && $function->isDeprecated()) {
675  $message = sprintf('Twig Function "%s" is deprecated', $function->getName());
676  if (!is_bool($function->getDeprecatedVersion())) {
677  $message .= sprintf(' since version %s', $function->getDeprecatedVersion());
678  }
679  if ($function->getAlternative()) {
680  $message .= sprintf('. Use "%s" instead', $function->getAlternative());
681  }
682  $src = $this->parser->getStream()->getSourceContext();
683  $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line);
684 
685  @trigger_error($message, E_USER_DEPRECATED);
686  }
687 
688  if ($function instanceof Twig_SimpleFunction) {
689  return $function->getNodeClass();
690  }
691 
692  return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
693  }
694 
695  protected function getFilterNodeClass($name, $line)
696  {
697  if (false === $filter = $this->env->getFilter($name)) {
698  $e = new Twig_Error_Syntax(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
699  $e->addSuggestions($name, array_keys($this->env->getFilters()));
700 
701  throw $e;
702  }
703 
704  if ($filter instanceof Twig_SimpleFilter && $filter->isDeprecated()) {
705  $message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
706  if (!is_bool($filter->getDeprecatedVersion())) {
707  $message .= sprintf(' since version %s', $filter->getDeprecatedVersion());
708  }
709  if ($filter->getAlternative()) {
710  $message .= sprintf('. Use "%s" instead', $filter->getAlternative());
711  }
712  $src = $this->parser->getStream()->getSourceContext();
713  $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line);
714 
715  @trigger_error($message, E_USER_DEPRECATED);
716  }
717 
718  if ($filter instanceof Twig_SimpleFilter) {
719  return $filter->getNodeClass();
720  }
721 
722  return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
723  }
724 
725  // checks that the node only contains "constant" elements
726  protected function checkConstantExpression(Twig_NodeInterface $node)
727  {
728  if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array
729  || $node instanceof Twig_Node_Expression_Unary_Neg || $node instanceof Twig_Node_Expression_Unary_Pos
730  )) {
731  return false;
732  }
733 
734  foreach ($node as $n) {
735  if (!$this->checkConstantExpression($n)) {
736  return false;
737  }
738  }
739 
740  return true;
741  }
742 }
743 
744 class_alias('Twig_ExpressionParser', 'Twig\ExpressionParser', false);
Represents a node in the AST.
addElement(Twig_Node_Expression $value, Twig_Node_Expression $key=null)
Definition: Array.php:54
isUnary(Twig_Token $token)
Represents a template function.
parseExpression($precedence=0)
const PUNCTUATION_TYPE
Definition: Token.php:36
Represents a node in the AST.
Definition: Node.php:18
$type
getLine()
Definition: Node.php:129
Default parser implementation.
Definition: Parser.php:18
isBinary(Twig_Token $token)
Parses expressions.
parseArguments($namedArguments=false, $definition=false)
Parses arguments.
test($type, $values=null)
Tests the current token for a type and/or a value.
Definition: Token.php:70
getFilterNodeClass($name, $line)
parseTestExpression(Twig_NodeInterface $node)
addSuggestions($name, array $items)
Tweaks the error message to include suggestions.
Definition: Syntax.php:26
Represents a template test as a Node.
Definition: Node.php:21
$stream
PHP stream implementation.
Represents a template filter.
Represents a template function as a node.
Definition: Node.php:23
Exception thrown when a syntax error occurs during lexing or parsing of a template.
Definition: Syntax.php:18
const STRING_TYPE
Definition: Token.php:34
if($format !==null) $name
Definition: metadata.php:146
catch(Exception $e) $message
__construct(Twig_Parser $parser, $env=null)
getFunctionNodeClass($name, $line)
checkConstantExpression(Twig_NodeInterface $node)
getEnvironment()
Definition: Parser.php:44
Represents a template filter as a node.
Definition: Node.php:23
Represents a parent node.
Definition: Parent.php:18
$n
Definition: RandomTest.php:85
getValue()
Definition: Token.php:103
Create styles array
The data for the language used.
parseNotTestExpression(Twig_NodeInterface $node)
getFunctionNode($name, $line)
const INTERPOLATION_END_TYPE
Definition: Token.php:38
const NUMBER_TYPE
Definition: Token.php:33
static typeToEnglish($type)
Returns the English representation of a given type.
Definition: Token.php:172
$function
Definition: cas.php:28
Represents a block call node.
Represents a template test.
Definition: SimpleTest.php:19
const REGEX_NAME
Definition: Lexer.php:45
Stores the Twig configuration.
Definition: Environment.php:17
const OPERATOR_TYPE
Definition: Token.php:35
$key
Definition: croninfo.php:18
const NAME_TYPE
Definition: Token.php:32
if(function_exists('posix_getuid') &&posix_getuid()===0) if(!array_key_exists('t', $options)) $tag
Definition: cron.php:35
const INTERPOLATION_START_TYPE
Definition: Token.php:37
parseFilterExpressionRaw($node, $tag=null)
$test
Definition: Utf8Test.php:84