PEEL Shopping
Open source ecommerce : PEEL Shopping
ExpressionParser.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of Twig.
5  *
6  * (c) 2009 Fabien Potencier
7  * (c) 2009 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 
24 {
25  const OPERATOR_LEFT = 1;
26  const OPERATOR_RIGHT = 2;
27 
28  protected $parser;
29  protected $unaryOperators;
30  protected $binaryOperators;
31 
33  {
34  $this->parser = $parser;
35  $this->unaryOperators = $unaryOperators;
36  $this->binaryOperators = $binaryOperators;
37  }
38 
39  public function parseExpression($precedence = 0)
40  {
41  $expr = $this->getPrimary();
42  $token = $this->parser->getCurrentToken();
43  while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
44  $op = $this->binaryOperators[$token->getValue()];
45  $this->parser->getStream()->next();
46 
47  if (isset($op['callable'])) {
48  $expr = call_user_func($op['callable'], $this->parser, $expr);
49  } else {
50  $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
51  $class = $op['class'];
52  $expr = new $class($expr, $expr1, $token->getLine());
53  }
54 
55  $token = $this->parser->getCurrentToken();
56  }
57 
58  if (0 === $precedence) {
59  return $this->parseConditionalExpression($expr);
60  }
61 
62  return $expr;
63  }
64 
65  protected function getPrimary()
66  {
67  $token = $this->parser->getCurrentToken();
68 
69  if ($this->isUnary($token)) {
70  $operator = $this->unaryOperators[$token->getValue()];
71  $this->parser->getStream()->next();
72  $expr = $this->parseExpression($operator['precedence']);
73  $class = $operator['class'];
74 
75  return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
76  } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
77  $this->parser->getStream()->next();
78  $expr = $this->parseExpression();
79  $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
80 
81  return $this->parsePostfixExpression($expr);
82  }
83 
84  return $this->parsePrimaryExpression();
85  }
86 
87  protected function parseConditionalExpression($expr)
88  {
89  while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) {
90  $this->parser->getStream()->next();
91  if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
92  $expr2 = $this->parseExpression();
93  if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
94  $this->parser->getStream()->next();
95  $expr3 = $this->parseExpression();
96  } else {
97  $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
98  }
99  } else {
100  $this->parser->getStream()->next();
101  $expr2 = $expr;
102  $expr3 = $this->parseExpression();
103  }
104 
105  $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
106  }
107 
108  return $expr;
109  }
110 
111  protected function isUnary(Twig_Token $token)
112  {
113  return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
114  }
115 
116  protected function isBinary(Twig_Token $token)
117  {
118  return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
119  }
120 
121  public function parsePrimaryExpression()
122  {
123  $token = $this->parser->getCurrentToken();
124  switch ($token->getType()) {
126  $this->parser->getStream()->next();
127  switch ($token->getValue()) {
128  case 'true':
129  case 'TRUE':
130  $node = new Twig_Node_Expression_Constant(true, $token->getLine());
131  break;
132 
133  case 'false':
134  case 'FALSE':
135  $node = new Twig_Node_Expression_Constant(false, $token->getLine());
136  break;
137 
138  case 'none':
139  case 'NONE':
140  case 'null':
141  case 'NULL':
142  $node = new Twig_Node_Expression_Constant(null, $token->getLine());
143  break;
144 
145  default:
146  if ('(' === $this->parser->getCurrentToken()->getValue()) {
147  $node = $this->getFunctionNode($token->getValue(), $token->getLine());
148  } else {
149  $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
150  }
151  }
152  break;
153 
155  $this->parser->getStream()->next();
156  $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
157  break;
158 
161  $node = $this->parseStringExpression();
162  break;
163 
164  default:
165  if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
166  $node = $this->parseArrayExpression();
167  } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
168  $node = $this->parseHashExpression();
169  } else {
170  throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
171  }
172  }
173 
174  return $this->parsePostfixExpression($node);
175  }
176 
177  public function parseStringExpression()
178  {
179  $stream = $this->parser->getStream();
180 
181  $nodes = array();
182  // a string cannot be followed by another string in a single expression
183  $nextCanBeString = true;
184  while (true) {
185  if ($stream->test(Twig_Token::STRING_TYPE) && $nextCanBeString) {
186  $token = $stream->next();
187  $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
188  $nextCanBeString = false;
189  } elseif ($stream->test(Twig_Token::INTERPOLATION_START_TYPE)) {
190  $stream->next();
191  $nodes[] = $this->parseExpression();
192  $stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
193  $nextCanBeString = true;
194  } else {
195  break;
196  }
197  }
198 
199  $expr = array_shift($nodes);
200  foreach ($nodes as $node) {
201  $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine());
202  }
203 
204  return $expr;
205  }
206 
207  public function parseArrayExpression()
208  {
209  $stream = $this->parser->getStream();
210  $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
211 
212  $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
213  $first = true;
214  while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
215  if (!$first) {
216  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
217 
218  // trailing ,?
219  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
220  break;
221  }
222  }
223  $first = false;
224 
225  $node->addElement($this->parseExpression());
226  }
227  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
228 
229  return $node;
230  }
231 
232  public function parseHashExpression()
233  {
234  $stream = $this->parser->getStream();
235  $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
236 
237  $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
238  $first = true;
239  while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
240  if (!$first) {
241  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
242 
243  // trailing ,?
244  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
245  break;
246  }
247  }
248  $first = false;
249 
250  // a hash key can be:
251  //
252  // * a number -- 12
253  // * a string -- 'a'
254  // * a name, which is equivalent to a string -- a
255  // * an expression, which must be enclosed in parentheses -- (1 + 2)
256  if ($stream->test(Twig_Token::STRING_TYPE) || $stream->test(Twig_Token::NAME_TYPE) || $stream->test(Twig_Token::NUMBER_TYPE)) {
257  $token = $stream->next();
258  $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
259  } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
260  $key = $this->parseExpression();
261  } else {
262  $current = $stream->getCurrent();
263 
264  throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType(), $current->getLine()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
265  }
266 
267  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
268  $value = $this->parseExpression();
269 
270  $node->addElement($value, $key);
271  }
272  $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
273 
274  return $node;
275  }
276 
277  public function parsePostfixExpression($node)
278  {
279  while (true) {
280  $token = $this->parser->getCurrentToken();
281  if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
282  if ('.' == $token->getValue() || '[' == $token->getValue()) {
283  $node = $this->parseSubscriptExpression($node);
284  } elseif ('|' == $token->getValue()) {
285  $node = $this->parseFilterExpression($node);
286  } else {
287  break;
288  }
289  } else {
290  break;
291  }
292  }
293 
294  return $node;
295  }
296 
297  public function getFunctionNode($name, $line)
298  {
299  switch ($name) {
300  case 'parent':
301  $args = $this->parseArguments();
302  if (!count($this->parser->getBlockStack())) {
303  throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
304  }
305 
306  if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
307  throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
308  }
309 
310  return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
311  case 'block':
312  return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
313  case 'attribute':
314  $args = $this->parseArguments();
315  if (count($args) < 2) {
316  throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
317  }
318 
319  return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_TemplateInterface::ANY_CALL, $line);
320  default:
321  if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
322  $arguments = new Twig_Node_Expression_Array(array(), $line);
323  foreach ($this->parseArguments() as $n) {
324  $arguments->addElement($n);
325  }
326 
327  $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
328  $node->setAttribute('safe', true);
329 
330  return $node;
331  }
332 
333  $args = $this->parseArguments(true);
334  $class = $this->getFunctionNodeClass($name, $line);
335 
336  return new $class($name, $args, $line);
337  }
338  }
339 
340  public function parseSubscriptExpression($node)
341  {
342  $stream = $this->parser->getStream();
343  $token = $stream->next();
344  $lineno = $token->getLine();
345  $arguments = new Twig_Node_Expression_Array(array(), $lineno);
347  if ($token->getValue() == '.') {
348  $token = $stream->next();
349  if (
350  $token->getType() == Twig_Token::NAME_TYPE
351  ||
352  $token->getType() == Twig_Token::NUMBER_TYPE
353  ||
354  ($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
355  ) {
356  $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
357 
358  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
360  foreach ($this->parseArguments() as $n) {
361  $arguments->addElement($n);
362  }
363  }
364  } else {
365  throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
366  }
367 
368  if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
369  if (!$arg instanceof Twig_Node_Expression_Constant) {
370  throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
371  }
372 
373  $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
374  $node->setAttribute('safe', true);
375 
376  return $node;
377  }
378  } else {
380 
381  // slice?
382  $slice = false;
383  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
384  $slice = true;
385  $arg = new Twig_Node_Expression_Constant(0, $token->getLine());
386  } else {
387  $arg = $this->parseExpression();
388  }
389 
390  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
391  $slice = true;
392  $stream->next();
393  }
394 
395  if ($slice) {
396  if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
397  $length = new Twig_Node_Expression_Constant(null, $token->getLine());
398  } else {
399  $length = $this->parseExpression();
400  }
401 
402  $class = $this->getFilterNodeClass('slice', $token->getLine());
403  $arguments = new Twig_Node(array($arg, $length));
404  $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
405 
406  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
407 
408  return $filter;
409  }
410 
411  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
412  }
413 
414  return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
415  }
416 
417  public function parseFilterExpression($node)
418  {
419  $this->parser->getStream()->next();
420 
421  return $this->parseFilterExpressionRaw($node);
422  }
423 
424  public function parseFilterExpressionRaw($node, $tag = null)
425  {
426  while (true) {
427  $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
428 
429  $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
430  if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
431  $arguments = new Twig_Node();
432  } else {
433  $arguments = $this->parseArguments(true);
434  }
435 
436  $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
437 
438  $node = new $class($node, $name, $arguments, $token->getLine(), $tag);
439 
440  if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
441  break;
442  }
443 
444  $this->parser->getStream()->next();
445  }
446 
447  return $node;
448  }
449 
456  public function parseArguments($namedArguments = false, $definition = false)
457  {
458  $args = array();
459  $stream = $this->parser->getStream();
460 
461  $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
462  while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
463  if (!empty($args)) {
464  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
465  }
466 
467  if ($definition) {
468  $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
469  $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
470  } else {
471  $value = $this->parseExpression();
472  }
473 
474  $name = null;
475  if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) {
476  $token = $stream->next();
477  if (!$value instanceof Twig_Node_Expression_Name) {
478  throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename());
479  }
480  $name = $value->getAttribute('name');
481 
482  if ($definition) {
483  $value = $this->parsePrimaryExpression();
484 
485  if (!$this->checkConstantExpression($value)) {
486  throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename());
487  }
488  } else {
489  $value = $this->parseExpression();
490  }
491  }
492 
493  if ($definition) {
494  if (null === $name) {
495  $name = $value->getAttribute('name');
496  $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
497  }
498  $args[$name] = $value;
499  } else {
500  if (null === $name) {
501  $args[] = $value;
502  } else {
503  $args[$name] = $value;
504  }
505  }
506  }
507  $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
508 
509  return new Twig_Node($args);
510  }
511 
512  public function parseAssignmentExpression()
513  {
514  $targets = array();
515  while (true) {
516  $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
517  if (in_array($token->getValue(), array('true', 'false', 'none'))) {
518  throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
519  }
520  $targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
521 
522  if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
523  break;
524  }
525  $this->parser->getStream()->next();
526  }
527 
528  return new Twig_Node($targets);
529  }
530 
531  public function parseMultitargetExpression()
532  {
533  $targets = array();
534  while (true) {
535  $targets[] = $this->parseExpression();
536  if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
537  break;
538  }
539  $this->parser->getStream()->next();
540  }
541 
542  return new Twig_Node($targets);
543  }
544 
545  protected function getFunctionNodeClass($name, $line)
546  {
547  $env = $this->parser->getEnvironment();
548 
549  if (false === $function = $env->getFunction($name)) {
550  $message = sprintf('The function "%s" does not exist', $name);
551  if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
552  $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
553  }
554 
555  throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
556  }
557 
558  if ($function instanceof Twig_SimpleFunction) {
559  return $function->getNodeClass();
560  }
561 
562  return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
563  }
564 
565  protected function getFilterNodeClass($name, $line)
566  {
567  $env = $this->parser->getEnvironment();
568 
569  if (false === $filter = $env->getFilter($name)) {
570  $message = sprintf('The filter "%s" does not exist', $name);
571  if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) {
572  $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
573  }
574 
575  throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
576  }
577 
578  if ($filter instanceof Twig_SimpleFilter) {
579  return $filter->getNodeClass();
580  }
581 
582  return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
583  }
584 
585  // checks that the node only contains "constant" elements
586  protected function checkConstantExpression(Twig_NodeInterface $node)
587  {
588  if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) {
589  return false;
590  }
591 
592  foreach ($node as $n) {
593  if (!$this->checkConstantExpression($n)) {
594  return false;
595  }
596  }
597 
598  return true;
599  }
600 }
getLine()
Definition: Node.php:109
Represents a template function as a node.
Definition: Node.php:20
isBinary(Twig_Token $token)
if($rub=fetch_assoc($rub_query)) if(check_if_module_active('url_rewriting')) $class
Definition: index.php:68
getFunctionNodeClass($name, $line)
getFilterNodeClass($name, $line)
getFunctionNode($name, $line)
Represents a node in the AST.
Definition: Node.php:18
Parses expressions.
Represents a template function.
__construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators)
const OPERATOR_TYPE
Definition: Token.php:33
parseExpression($precedence=0)
Exception thrown when a syntax error occurs during lexing or parsing of a template.
Definition: Syntax.php:18
const REGEX_NAME
Definition: Lexer.php:42
Default parser implementation.
Definition: Parser.php:18
const INTERPOLATION_END_TYPE
Definition: Token.php:36
if(strlen($date2)== '10') if($type== 'users-by-age'&&a_priv('admin_users', true)) elseif($type== 'forums-count'&&a_priv('admin_content', true)) elseif($type== 'forums-categories'&&a_priv('admin_content', true)) elseif($type== 'users-count'&&a_priv('admin_users', true)) elseif($type== 'product-categories'&&a_priv('admin_products', true)) elseif($type== 'users-by-sex'&&a_priv('admin_users', true)) elseif($type== 'users-by-country'&&a_priv('admin_users', true)) elseif($type== 'sales'&&a_priv('admin_sales', true))
Definition: chart-data.php:160
static typeToEnglish($type, $line=-1)
Returns the english representation of a given type.
Definition: Token.php:185
setAttribute($name, $value)
Sets an attribute.
Definition: Node.php:153
addElement(Twig_Node_Expression $value, Twig_Node_Expression $key=null)
Definition: Array.php:54
Represents a parent node.
Definition: Parent.php:18
Represents a template filter as a node.
Definition: Node.php:20
Represents a node in the AST.
const INTERPOLATION_START_TYPE
Definition: Token.php:35
Represents a Token.
Definition: Token.php:18
checkConstantExpression(Twig_NodeInterface $node)
const NAME_TYPE
Definition: Token.php:30
getValue()
Gets the token value.
Definition: Token.php:114
test($type, $values=null)
Tests the current token for a type and/or a value.
Definition: Token.php:75
const PUNCTUATION_TYPE
Definition: Token.php:34
Represents a block call node.
Represents a template filter.
parseFilterExpressionRaw($node, $tag=null)
isUnary(Twig_Token $token)
parseArguments($namedArguments=false, $definition=false)
Parses arguments.
const NUMBER_TYPE
Definition: Token.php:31
const STRING_TYPE
Definition: Token.php:32

This documentation for Open ecommerce PEEL Shopping and PEEL.fr has been generated by Doxygen on Thu Oct 15 2015 14:41:18 - Peel ecommerce is a product of Agence web Advisto SAS. All rights reserved.