PluginProbe
Responsive Menu – Create Mobile-Friendly Menu / 3.1.12
Responsive Menu – Create Mobile-Friendly Menu v3.1.12
4.7.3 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.10 4.1.11 4.1.12 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 All 90 releases
responsive-menu / vendor / twig / twig / lib / Twig / ExpressionParser.php

ExpressionParser.php in Responsive Menu – Create Mobile-Friendly Menu 3.1.12, at vendor/twig/twig/lib/Twig/ExpressionParser.php

740 lines 29.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 * (c) Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13 /**
14 * Parses expressions.
15 *
16 * This parser implements a "Precedence climbing" algorithm.
17 *
18 * @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
19 * @see http://en.wikipedia.org/wiki/Operator-precedence_parser
20 *
21 * @author Fabien Potencier <fabien@symfony.com>
22 *
23 * @internal
24 */
25 class Twig_ExpressionParser
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()) {
140 case Twig_Token::NAME_TYPE:
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
169 case Twig_Token::NUMBER_TYPE:
170 $this->parser->getStream()->next();
171 $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
172 break;
173
174 case Twig_Token::STRING_TYPE:
175 case Twig_Token::INTERPOLATION_START_TYPE:
176 $node = $this->parseStringExpression();
177 break;
178
179 case Twig_Token::OPERATOR_TYPE:
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 default:
203 if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
204 $node = $this->parseArrayExpression();
205 } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
206 $node = $this->parseHashExpression();
207 } else {
208 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());
209 }
210 }
211
212 return $this->parsePostfixExpression($node);
213 }
214
215 public function parseStringExpression()
216 {
217 $stream = $this->parser->getStream();
218
219 $nodes = array();
220 // a string cannot be followed by another string in a single expression
221 $nextCanBeString = true;
222 while (true) {
223 if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) {
224 $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
225 $nextCanBeString = false;
226 } elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) {
227 $nodes[] = $this->parseExpression();
228 $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
229 $nextCanBeString = true;
230 } else {
231 break;
232 }
233 }
234
235 $expr = array_shift($nodes);
236 foreach ($nodes as $node) {
237 $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getTemplateLine());
238 }
239
240 return $expr;
241 }
242
243 public function parseArrayExpression()
244 {
245 $stream = $this->parser->getStream();
246 $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
247
248 $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
249 $first = true;
250 while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
251 if (!$first) {
252 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
253
254 // trailing ,?
255 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
256 break;
257 }
258 }
259 $first = false;
260
261 $node->addElement($this->parseExpression());
262 }
263 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
264
265 return $node;
266 }
267
268 public function parseHashExpression()
269 {
270 $stream = $this->parser->getStream();
271 $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
272
273 $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
274 $first = true;
275 while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
276 if (!$first) {
277 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
278
279 // trailing ,?
280 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
281 break;
282 }
283 }
284 $first = false;
285
286 // a hash key can be:
287 //
288 // * a number -- 12
289 // * a string -- 'a'
290 // * a name, which is equivalent to a string -- a
291 // * an expression, which must be enclosed in parentheses -- (1 + 2)
292 if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) {
293 $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
294 } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
295 $key = $this->parseExpression();
296 } else {
297 $current = $stream->getCurrent();
298
299 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());
300 }
301
302 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
303 $value = $this->parseExpression();
304
305 $node->addElement($value, $key);
306 }
307 $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
308
309 return $node;
310 }
311
312 public function parsePostfixExpression($node)
313 {
314 while (true) {
315 $token = $this->parser->getCurrentToken();
316 if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
317 if ('.' == $token->getValue() || '[' == $token->getValue()) {
318 $node = $this->parseSubscriptExpression($node);
319 } elseif ('|' == $token->getValue()) {
320 $node = $this->parseFilterExpression($node);
321 } else {
322 break;
323 }
324 } else {
325 break;
326 }
327 }
328
329 return $node;
330 }
331
332 public function getFunctionNode($name, $line)
333 {
334 switch ($name) {
335 case 'parent':
336 $this->parseArguments();
337 if (!count($this->parser->getBlockStack())) {
338 throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext());
339 }
340
341 if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
342 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());
343 }
344
345 return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
346 case 'block':
347 $args = $this->parseArguments();
348 if (count($args) < 1) {
349 throw new Twig_Error_Syntax('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext());
350 }
351
352 return new Twig_Node_Expression_BlockReference($args->getNode(0), count($args) > 1 ? $args->getNode(1) : null, $line);
353 case 'attribute':
354 $args = $this->parseArguments();
355 if (count($args) < 2) {
356 throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext());
357 }
358
359 return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line);
360 default:
361 if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
362 $arguments = new Twig_Node_Expression_Array(array(), $line);
363 foreach ($this->parseArguments() as $n) {
364 $arguments->addElement($n);
365 }
366
367 $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
368 $node->setAttribute('safe', true);
369
370 return $node;
371 }
372
373 $args = $this->parseArguments(true);
374 $class = $this->getFunctionNodeClass($name, $line);
375
376 return new $class($name, $args, $line);
377 }
378 }
379
380 public function parseSubscriptExpression($node)
381 {
382 $stream = $this->parser->getStream();
383 $token = $stream->next();
384 $lineno = $token->getLine();
385 $arguments = new Twig_Node_Expression_Array(array(), $lineno);
386 $type = Twig_Template::ANY_CALL;
387 if ($token->getValue() == '.') {
388 $token = $stream->next();
389 if (
390 $token->getType() == Twig_Token::NAME_TYPE
391 ||
392 $token->getType() == Twig_Token::NUMBER_TYPE
393 ||
394 ($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
395 ) {
396 $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
397
398 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
399 $type = Twig_Template::METHOD_CALL;
400 foreach ($this->parseArguments() as $n) {
401 $arguments->addElement($n);
402 }
403 }
404 } else {
405 throw new Twig_Error_Syntax('Expected name or number.', $lineno, $stream->getSourceContext());
406 }
407
408 if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
409 if (!$arg instanceof Twig_Node_Expression_Constant) {
410 throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext());
411 }
412
413 $name = $arg->getAttribute('value');
414
415 if ($this->parser->isReservedMacroName($name)) {
416 throw new Twig_Error_Syntax(sprintf('"%s" cannot be called as macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext());
417 }
418
419 $node = new Twig_Node_Expression_MethodCall($node, 'get'.$name, $arguments, $lineno);
420 $node->setAttribute('safe', true);
421
422 return $node;
423 }
424 } else {
425 $type = Twig_Template::ARRAY_CALL;
426
427 // slice?
428 $slice = false;
429 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
430 $slice = true;
431 $arg = new Twig_Node_Expression_Constant(0, $token->getLine());
432 } else {
433 $arg = $this->parseExpression();
434 }
435
436 if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) {
437 $slice = true;
438 }
439
440 if ($slice) {
441 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
442 $length = new Twig_Node_Expression_Constant(null, $token->getLine());
443 } else {
444 $length = $this->parseExpression();
445 }
446
447 $class = $this->getFilterNodeClass('slice', $token->getLine());
448 $arguments = new Twig_Node(array($arg, $length));
449 $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
450
451 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
452
453 return $filter;
454 }
455
456 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
457 }
458
459 return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
460 }
461
462 public function parseFilterExpression($node)
463 {
464 $this->parser->getStream()->next();
465
466 return $this->parseFilterExpressionRaw($node);
467 }
468
469 public function parseFilterExpressionRaw($node, $tag = null)
470 {
471 while (true) {
472 $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
473
474 $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
475 if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
476 $arguments = new Twig_Node();
477 } else {
478 $arguments = $this->parseArguments(true);
479 }
480
481 $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
482
483 $node = new $class($node, $name, $arguments, $token->getLine(), $tag);
484
485 if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
486 break;
487 }
488
489 $this->parser->getStream()->next();
490 }
491
492 return $node;
493 }
494
495 /**
496 * Parses arguments.
497 *
498 * @param bool $namedArguments Whether to allow named arguments or not
499 * @param bool $definition Whether we are parsing arguments for a function definition
500 *
501 * @return Twig_Node
502 *
503 * @throws Twig_Error_Syntax
504 */
505 public function parseArguments($namedArguments = false, $definition = false)
506 {
507 $args = array();
508 $stream = $this->parser->getStream();
509
510 $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
511 while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
512 if (!empty($args)) {
513 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
514 }
515
516 if ($definition) {
517 $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
518 $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
519 } else {
520 $value = $this->parseExpression();
521 }
522
523 $name = null;
524 if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) {
525 if (!$value instanceof Twig_Node_Expression_Name) {
526 throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given.', get_class($value)), $token->getLine(), $stream->getSourceContext());
527 }
528 $name = $value->getAttribute('name');
529
530 if ($definition) {
531 $value = $this->parsePrimaryExpression();
532
533 if (!$this->checkConstantExpression($value)) {
534 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());
535 }
536 } else {
537 $value = $this->parseExpression();
538 }
539 }
540
541 if ($definition) {
542 if (null === $name) {
543 $name = $value->getAttribute('name');
544 $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
545 }
546 $args[$name] = $value;
547 } else {
548 if (null === $name) {
549 $args[] = $value;
550 } else {
551 $args[$name] = $value;
552 }
553 }
554 }
555 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
556
557 return new Twig_Node($args);
558 }
559
560 public function parseAssignmentExpression()
561 {
562 $stream = $this->parser->getStream();
563 $targets = array();
564 while (true) {
565 $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
566 $value = $token->getValue();
567 if (in_array(strtolower($value), array('true', 'false', 'none', 'null'))) {
568 throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext());
569 }
570 $targets[] = new Twig_Node_Expression_AssignName($value, $token->getLine());
571
572 if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
573 break;
574 }
575 }
576
577 return new Twig_Node($targets);
578 }
579
580 public function parseMultitargetExpression()
581 {
582 $targets = array();
583 while (true) {
584 $targets[] = $this->parseExpression();
585 if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) {
586 break;
587 }
588 }
589
590 return new Twig_Node($targets);
591 }
592
593 private function parseNotTestExpression(Twig_NodeInterface $node)
594 {
595 return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine());
596 }
597
598 private function parseTestExpression(Twig_NodeInterface $node)
599 {
600 $stream = $this->parser->getStream();
601 list($name, $test) = $this->getTest($node->getTemplateLine());
602
603 $class = $this->getTestNodeClass($test);
604 $arguments = null;
605 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
606 $arguments = $this->parser->getExpressionParser()->parseArguments(true);
607 }
608
609 return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine());
610 }
611
612 private function getTest($line)
613 {
614 $stream = $this->parser->getStream();
615 $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
616
617 if ($test = $this->env->getTest($name)) {
618 return array($name, $test);
619 }
620
621 if ($stream->test(Twig_Token::NAME_TYPE)) {
622 // try 2-words tests
623 $name = $name.' '.$this->parser->getCurrentToken()->getValue();
624
625 if ($test = $this->env->getTest($name)) {
626 $stream->next();
627
628 return array($name, $test);
629 }
630 }
631
632 $e = new Twig_Error_Syntax(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext());
633 $e->addSuggestions($name, array_keys($this->env->getTests()));
634
635 throw $e;
636 }
637
638 private function getTestNodeClass($test)
639 {
640 if ($test instanceof Twig_SimpleTest && $test->isDeprecated()) {
641 $stream = $this->parser->getStream();
642 $message = sprintf('Twig Test "%s" is deprecated', $test->getName());
643 if (!is_bool($test->getDeprecatedVersion())) {
644 $message .= sprintf(' since version %s', $test->getDeprecatedVersion());
645 }
646 if ($test->getAlternative()) {
647 $message .= sprintf('. Use "%s" instead', $test->getAlternative());
648 }
649 $src = $stream->getSourceContext();
650 $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $stream->getCurrent()->getLine());
651
652 @trigger_error($message, E_USER_DEPRECATED);
653 }
654
655 if ($test instanceof Twig_SimpleTest) {
656 return $test->getNodeClass();
657 }
658
659 return $test instanceof Twig_Test_Node ? $test->getClass() : 'Twig_Node_Expression_Test';
660 }
661
662 protected function getFunctionNodeClass($name, $line)
663 {
664 if (false === $function = $this->env->getFunction($name)) {
665 $e = new Twig_Error_Syntax(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext());
666 $e->addSuggestions($name, array_keys($this->env->getFunctions()));
667
668 throw $e;
669 }
670
671 if ($function instanceof Twig_SimpleFunction && $function->isDeprecated()) {
672 $message = sprintf('Twig Function "%s" is deprecated', $function->getName());
673 if (!is_bool($function->getDeprecatedVersion())) {
674 $message .= sprintf(' since version %s', $function->getDeprecatedVersion());
675 }
676 if ($function->getAlternative()) {
677 $message .= sprintf('. Use "%s" instead', $function->getAlternative());
678 }
679 $src = $this->parser->getStream()->getSourceContext();
680 $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line);
681
682 @trigger_error($message, E_USER_DEPRECATED);
683 }
684
685 if ($function instanceof Twig_SimpleFunction) {
686 return $function->getNodeClass();
687 }
688
689 return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
690 }
691
692 protected function getFilterNodeClass($name, $line)
693 {
694 if (false === $filter = $this->env->getFilter($name)) {
695 $e = new Twig_Error_Syntax(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext());
696 $e->addSuggestions($name, array_keys($this->env->getFilters()));
697
698 throw $e;
699 }
700
701 if ($filter instanceof Twig_SimpleFilter && $filter->isDeprecated()) {
702 $message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
703 if (!is_bool($filter->getDeprecatedVersion())) {
704 $message .= sprintf(' since version %s', $filter->getDeprecatedVersion());
705 }
706 if ($filter->getAlternative()) {
707 $message .= sprintf('. Use "%s" instead', $filter->getAlternative());
708 }
709 $src = $this->parser->getStream()->getSourceContext();
710 $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line);
711
712 @trigger_error($message, E_USER_DEPRECATED);
713 }
714
715 if ($filter instanceof Twig_SimpleFilter) {
716 return $filter->getNodeClass();
717 }
718
719 return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
720 }
721
722 // checks that the node only contains "constant" elements
723 protected function checkConstantExpression(Twig_NodeInterface $node)
724 {
725 if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array
726 || $node instanceof Twig_Node_Expression_Unary_Neg || $node instanceof Twig_Node_Expression_Unary_Pos
727 )) {
728 return false;
729 }
730
731 foreach ($node as $n) {
732 if (!$this->checkConstantExpression($n)) {
733 return false;
734 }
735 }
736
737 return true;
738 }
739 }
740