Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
50.00% covered (danger)
50.00%
5 / 10
CRAP
74.56% covered (warning)
74.56%
126 / 169
Parser
0.00% covered (danger)
0.00%
0 / 1
50.00% covered (danger)
50.00%
5 / 10
110.52
74.56% covered (warning)
74.56%
126 / 169
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
30 / 30
 parse
0.00% covered (danger)
0.00%
0 / 1
2.02
83.33% covered (warning)
83.33%
5 / 6
 parseExpression
100.00% covered (success)
100.00%
1 / 1
6
100.00% covered (success)
100.00%
11 / 11
 getPrimary
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
12 / 12
 parseConditionalExpression
0.00% covered (danger)
0.00%
0 / 1
4.20
76.92% covered (warning)
76.92%
10 / 13
 parsePrimaryExpression
0.00% covered (danger)
0.00%
0 / 1
17.86
80.65% covered (warning)
80.65%
25 / 31
 parseArrayExpression
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 12
 parseHashExpression
0.00% covered (danger)
0.00%
0 / 1
72
0.00% covered (danger)
0.00%
0 / 21
 parsePostfixExpression
100.00% covered (success)
100.00%
1 / 1
9
100.00% covered (success)
100.00%
25 / 25
 parseArguments
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
8 / 8
<?php
/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace Symfony\Component\ExpressionLanguage;
/**
 * Parsers a token stream.
 *
 * This parser implements a "Precedence climbing" algorithm.
 *
 * @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
 * @see http://en.wikipedia.org/wiki/Operator-precedence_parser
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class Parser
{
    const OPERATOR_LEFT = 1;
    const OPERATOR_RIGHT = 2;
    private $stream;
    private $unaryOperators;
    private $binaryOperators;
    private $functions;
    private $names;
    public function __construct(array $functions)
    {
        $this->functions = $functions;
        $this->unaryOperators = [
            'not' => ['precedence' => 50],
            '!' => ['precedence' => 50],
            '-' => ['precedence' => 500],
            '+' => ['precedence' => 500],
        ];
        $this->binaryOperators = [
            'or' => ['precedence' => 10, 'associativity' => self::OPERATOR_LEFT],
            '||' => ['precedence' => 10, 'associativity' => self::OPERATOR_LEFT],
            'and' => ['precedence' => 15, 'associativity' => self::OPERATOR_LEFT],
            '&&' => ['precedence' => 15, 'associativity' => self::OPERATOR_LEFT],
            '|' => ['precedence' => 16, 'associativity' => self::OPERATOR_LEFT],
            '^' => ['precedence' => 17, 'associativity' => self::OPERATOR_LEFT],
            '&' => ['precedence' => 18, 'associativity' => self::OPERATOR_LEFT],
            '==' => ['precedence' => 20, 'associativity' => self::OPERATOR_LEFT],
            '===' => ['precedence' => 20, 'associativity' => self::OPERATOR_LEFT],
            '!=' => ['precedence' => 20, 'associativity' => self::OPERATOR_LEFT],
            '!==' => ['precedence' => 20, 'associativity' => self::OPERATOR_LEFT],
            '<' => ['precedence' => 20, 'associativity' => self::OPERATOR_LEFT],
            '>' => ['precedence' => 20, 'associativity' => self::OPERATOR_LEFT],
            '>=' => ['precedence' => 20, 'associativity' => self::OPERATOR_LEFT],
            '<=' => ['precedence' => 20, 'associativity' => self::OPERATOR_LEFT],
            'not in' => ['precedence' => 20, 'associativity' => self::OPERATOR_LEFT],
            'in' => ['precedence' => 20, 'associativity' => self::OPERATOR_LEFT],
            'matches' => ['precedence' => 20, 'associativity' => self::OPERATOR_LEFT],
            '..' => ['precedence' => 25, 'associativity' => self::OPERATOR_LEFT],
            '+' => ['precedence' => 30, 'associativity' => self::OPERATOR_LEFT],
            '-' => ['precedence' => 30, 'associativity' => self::OPERATOR_LEFT],
            '~' => ['precedence' => 40, 'associativity' => self::OPERATOR_LEFT],
            '*' => ['precedence' => 60, 'associativity' => self::OPERATOR_LEFT],
            '/' => ['precedence' => 60, 'associativity' => self::OPERATOR_LEFT],
            '%' => ['precedence' => 60, 'associativity' => self::OPERATOR_LEFT],
            '**' => ['precedence' => 200, 'associativity' => self::OPERATOR_RIGHT],
        ];
    }
    /**
     * Converts a token stream to a node tree.
     *
     * The valid names is an array where the values
     * are the names that the user can use in an expression.
     *
     * If the variable name in the compiled PHP code must be
     * different, define it as the key.
     *
     * For instance, ['this' => 'container'] means that the
     * variable 'container' can be used in the expression
     * but the compiled code will use 'this'.
     *
     * @return Node\Node A node tree
     *
     * @throws SyntaxError
     */
    public function parse(TokenStream $stream, array $names = [])
    {
        $this->stream = $stream;
        $this->names = $names;
        $node = $this->parseExpression();
        if (!$stream->isEOF()) {
            throw new SyntaxError(sprintf('Unexpected token "%s" of value "%s"', $stream->current->type, $stream->current->value), $stream->current->cursor, $stream->getExpression());
        }
        return $node;
    }
    public function parseExpression(int $precedence = 0)
    {
        $expr = $this->getPrimary();
        $token = $this->stream->current;
        while ($token->test(Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->value]) && $this->binaryOperators[$token->value]['precedence'] >= $precedence) {
            $op = $this->binaryOperators[$token->value];
            $this->stream->next();
            $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
            $expr = new Node\BinaryNode($token->value, $expr, $expr1);
            $token = $this->stream->current;
        }
        if (0 === $precedence) {