Changeset 1101:7273894e61b8 for inc/libs/twig/ExpressionParser.php
- Timestamp:
- 02/15/13 08:35:19 (13 years ago)
- Branch:
- twig
- Children:
- 1106:a4487f3ca4b4, 1147:2e5cb79e4782
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
inc/libs/twig/ExpressionParser.php
r991 r1101 90 90 while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) { 91 91 $this->parser->getStream()->next(); 92 $expr2 = $this->parseExpression(); 93 $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'The ternary operator must have a default value'); 94 $expr3 = $this->parseExpression(); 92 if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) { 93 $expr2 = $this->parseExpression(); 94 if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) { 95 $this->parser->getStream()->next(); 96 $expr3 = $this->parseExpression(); 97 } else { 98 $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine()); 99 } 100 } else { 101 $this->parser->getStream()->next(); 102 $expr2 = $expr; 103 $expr3 = $this->parseExpression(); 104 } 95 105 96 106 $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine()); … … 288 298 public function getFunctionNode($name, $line) 289 299 { 290 $args = $this->parseArguments();291 300 switch ($name) { 292 301 case 'parent': 302 $args = $this->parseArguments(); 293 303 if (!count($this->parser->getBlockStack())) { 294 304 throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename()); … … 301 311 return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line); 302 312 case 'block': 303 return new Twig_Node_Expression_BlockReference($ args->getNode(0), false, $line);313 return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line); 304 314 case 'attribute': 315 $args = $this->parseArguments(); 305 316 if (count($args) < 2) { 306 317 throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename()); … … 311 322 if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) { 312 323 $arguments = new Twig_Node_Expression_Array(array(), $line); 313 foreach ($ argsas $n) {324 foreach ($this->parseArguments() as $n) { 314 325 $arguments->addElement($n); 315 326 } … … 321 332 } 322 333 323 $class = $this->getFunctionNodeClass($name); 334 $args = $this->parseArguments(true); 335 $class = $this->getFunctionNodeClass($name, $line); 324 336 325 337 return new $class($name, $args, $line); … … 354 366 throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename()); 355 367 } 368 369 if ($node instanceof Twig_Node_Expression_Name && null !== $alias = $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { 370 if (!$arg instanceof Twig_Node_Expression_Constant) { 371 throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename()); 372 } 373 374 $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno); 375 $node->setAttribute('safe', true); 376 377 return $node; 378 } 356 379 } else { 357 380 $type = Twig_TemplateInterface::ARRAY_CALL; 358 381 359 $arg = $this->parseExpression();360 361 382 // slice? 383 $slice = false; 362 384 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { 385 $slice = true; 386 $arg = new Twig_Node_Expression_Constant(0, $token->getLine()); 387 } else { 388 $arg = $this->parseExpression(); 389 } 390 391 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { 392 $slice = true; 363 393 $stream->next(); 364 394 } 395 396 if ($slice) { 365 397 if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { 366 398 $length = new Twig_Node_Expression_Constant(null, $token->getLine()); … … 369 401 } 370 402 371 $class = $this->getFilterNodeClass('slice' );403 $class = $this->getFilterNodeClass('slice', $token->getLine()); 372 404 $arguments = new Twig_Node(array($arg, $length)); 373 405 $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine()); … … 379 411 380 412 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); 381 }382 383 if ($node instanceof Twig_Node_Expression_Name && null !== $alias = $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {384 $node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);385 $node->setAttribute('safe', true);386 387 return $node;388 413 } 389 414 … … 407 432 $arguments = new Twig_Node(); 408 433 } else { 409 $arguments = $this->parseArguments( );410 } 411 412 $class = $this->getFilterNodeClass($name->getAttribute('value') );434 $arguments = $this->parseArguments(true); 435 } 436 437 $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine()); 413 438 414 439 $node = new $class($node, $name, $arguments, $token->getLine(), $tag); … … 424 449 } 425 450 426 public function parseArguments() 451 /** 452 * Parses arguments. 453 * 454 * @param Boolean $namedArguments Whether to allow named arguments or not 455 * @param Boolean $definition Whether we are parsing arguments for a function definition 456 */ 457 public function parseArguments($namedArguments = false, $definition = false) 427 458 { 428 459 $args = array(); 429 460 $stream = $this->parser->getStream(); 430 461 431 $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must be opened by aparenthesis');462 $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); 432 463 while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) { 433 464 if (!empty($args)) { 434 465 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); 435 466 } 436 $args[] = $this->parseExpression(); 467 468 if ($definition) { 469 $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name'); 470 $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine()); 471 } else { 472 $value = $this->parseExpression(); 473 } 474 475 $name = null; 476 if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) { 477 $token = $stream->next(); 478 if (!$value instanceof Twig_Node_Expression_Name) { 479 throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename()); 480 } 481 $name = $value->getAttribute('name'); 482 483 if ($definition) { 484 $value = $this->parsePrimaryExpression(); 485 486 if (!$this->checkConstantExpression($value)) { 487 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()); 488 } 489 } else { 490 $value = $this->parseExpression(); 491 } 492 } 493 494 if ($definition) { 495 if (null === $name) { 496 $name = $value->getAttribute('name'); 497 $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine()); 498 } 499 $args[$name] = $value; 500 } else { 501 if (null === $name) { 502 $args[] = $value; 503 } else { 504 $args[$name] = $value; 505 } 506 } 437 507 } 438 508 $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis'); … … 474 544 } 475 545 476 protected function getFunctionNodeClass($name) 477 { 478 $functionMap = $this->parser->getEnvironment()->getFunctions(); 479 if (isset($functionMap[$name]) && $functionMap[$name] instanceof Twig_Function_Node) { 480 return $functionMap[$name]->getClass(); 481 } 482 483 return 'Twig_Node_Expression_Function'; 484 } 485 486 protected function getFilterNodeClass($name) 487 { 488 $filterMap = $this->parser->getEnvironment()->getFilters(); 489 if (isset($filterMap[$name]) && $filterMap[$name] instanceof Twig_Filter_Node) { 490 return $filterMap[$name]->getClass(); 491 } 492 493 return 'Twig_Node_Expression_Filter'; 546 protected function getFunctionNodeClass($name, $line) 547 { 548 $env = $this->parser->getEnvironment(); 549 550 if (false === $function = $env->getFunction($name)) { 551 $message = sprintf('The function "%s" does not exist', $name); 552 if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) { 553 $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); 554 } 555 556 throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename()); 557 } 558 559 if ($function instanceof Twig_SimpleFunction) { 560 return $function->getNodeClass(); 561 } 562 563 return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function'; 564 } 565 566 protected function getFilterNodeClass($name, $line) 567 { 568 $env = $this->parser->getEnvironment(); 569 570 if (false === $filter = $env->getFilter($name)) { 571 $message = sprintf('The filter "%s" does not exist', $name); 572 if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) { 573 $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); 574 } 575 576 throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename()); 577 } 578 579 if ($filter instanceof Twig_SimpleFilter) { 580 return $filter->getNodeClass(); 581 } 582 583 return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter'; 584 } 585 586 // checks that the node only contains "constant" elements 587 protected function checkConstantExpression(Twig_NodeInterface $node) 588 { 589 if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) { 590 return false; 591 } 592 593 foreach ($node as $n) { 594 if (!$this->checkConstantExpression($n)) { 595 return false; 596 } 597 } 598 599 return true; 494 600 } 495 601 }
Note: See TracChangeset
for help on using the changeset viewer.