Dotclear


Ignore:
Timestamp:
02/15/13 08:35:19 (13 years ago)
Author:
Dsls <dsls@…>
Branch:
twig
Children:
1106:a4487f3ca4b4, 1147:2e5cb79e4782
Message:

Twig 1.12.2

File:
1 edited

Legend:

Unmodified
Added
Removed
  • inc/libs/twig/ExpressionParser.php

    r991 r1101  
    9090        while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) { 
    9191            $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            } 
    95105 
    96106            $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine()); 
     
    288298    public function getFunctionNode($name, $line) 
    289299    { 
    290         $args = $this->parseArguments(); 
    291300        switch ($name) { 
    292301            case 'parent': 
     302                $args = $this->parseArguments(); 
    293303                if (!count($this->parser->getBlockStack())) { 
    294304                    throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename()); 
     
    301311                return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line); 
    302312            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); 
    304314            case 'attribute': 
     315                $args = $this->parseArguments(); 
    305316                if (count($args) < 2) { 
    306317                    throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename()); 
     
    311322                if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) { 
    312323                    $arguments = new Twig_Node_Expression_Array(array(), $line); 
    313                     foreach ($args as $n) { 
     324                    foreach ($this->parseArguments() as $n) { 
    314325                        $arguments->addElement($n); 
    315326                    } 
     
    321332                } 
    322333 
    323                 $class = $this->getFunctionNodeClass($name); 
     334                $args = $this->parseArguments(true); 
     335                $class = $this->getFunctionNodeClass($name, $line); 
    324336 
    325337                return new $class($name, $args, $line); 
     
    354366                throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename()); 
    355367            } 
     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            } 
    356379        } else { 
    357380            $type = Twig_TemplateInterface::ARRAY_CALL; 
    358381 
    359             $arg = $this->parseExpression(); 
    360  
    361382            // slice? 
     383            $slice = false; 
    362384            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; 
    363393                $stream->next(); 
    364  
     394            } 
     395 
     396            if ($slice) { 
    365397                if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { 
    366398                    $length = new Twig_Node_Expression_Constant(null, $token->getLine()); 
     
    369401                } 
    370402 
    371                 $class = $this->getFilterNodeClass('slice'); 
     403                $class = $this->getFilterNodeClass('slice', $token->getLine()); 
    372404                $arguments = new Twig_Node(array($arg, $length)); 
    373405                $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine()); 
     
    379411 
    380412            $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; 
    388413        } 
    389414 
     
    407432                $arguments = new Twig_Node(); 
    408433            } 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()); 
    413438 
    414439            $node = new $class($node, $name, $arguments, $token->getLine(), $tag); 
     
    424449    } 
    425450 
    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) 
    427458    { 
    428459        $args = array(); 
    429460        $stream = $this->parser->getStream(); 
    430461 
    431         $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must be opened by a parenthesis'); 
     462        $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); 
    432463        while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) { 
    433464            if (!empty($args)) { 
    434465                $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); 
    435466            } 
    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            } 
    437507        } 
    438508        $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis'); 
     
    474544    } 
    475545 
    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; 
    494600    } 
    495601} 
Note: See TracChangeset for help on using the changeset viewer.

Sites map