vendor/doctrine/orm/lib/Doctrine/ORM/Query/Parser.php line 405

Open in your IDE?
  1. <?php
  2. /*
  3.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7.  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14.  *
  15.  * This software consists of voluntary contributions made by many individuals
  16.  * and is licensed under the MIT license. For more information, see
  17.  * <http://www.doctrine-project.org>.
  18.  */
  19. namespace Doctrine\ORM\Query;
  20. use Doctrine\ORM\Mapping\ClassMetadata;
  21. use Doctrine\ORM\Query;
  22. use Doctrine\ORM\Query\AST\Functions;
  23. use function in_array;
  24. use function strpos;
  25. /**
  26.  * An LL(*) recursive-descent parser for the context-free grammar of the Doctrine Query Language.
  27.  * Parses a DQL query, reports any errors in it, and generates an AST.
  28.  *
  29.  * @since   2.0
  30.  * @author  Guilherme Blanco <[email protected]>
  31.  * @author  Jonathan Wage <[email protected]>
  32.  * @author  Roman Borschel <[email protected]>
  33.  * @author  Janne Vanhala <[email protected]>
  34.  * @author  Fabio B. Silva <[email protected]>
  35.  */
  36. class Parser
  37. {
  38.     /**
  39.      * READ-ONLY: Maps BUILT-IN string function names to AST class names.
  40.      *
  41.      * @var array
  42.      *
  43.      * @psalm-var class-string<Functions\FunctionNode>
  44.      */
  45.     private static $_STRING_FUNCTIONS = [
  46.         'concat'    => Functions\ConcatFunction::class,
  47.         'substring' => Functions\SubstringFunction::class,
  48.         'trim'      => Functions\TrimFunction::class,
  49.         'lower'     => Functions\LowerFunction::class,
  50.         'upper'     => Functions\UpperFunction::class,
  51.         'identity'  => Functions\IdentityFunction::class,
  52.     ];
  53.     /**
  54.      * READ-ONLY: Maps BUILT-IN numeric function names to AST class names.
  55.      *
  56.      * @var array
  57.      *
  58.      * @psalm-var class-string<Functions\FunctionNode>
  59.      */
  60.     private static $_NUMERIC_FUNCTIONS = [
  61.         'length'    => Functions\LengthFunction::class,
  62.         'locate'    => Functions\LocateFunction::class,
  63.         'abs'       => Functions\AbsFunction::class,
  64.         'sqrt'      => Functions\SqrtFunction::class,
  65.         'mod'       => Functions\ModFunction::class,
  66.         'size'      => Functions\SizeFunction::class,
  67.         'date_diff' => Functions\DateDiffFunction::class,
  68.         'bit_and'   => Functions\BitAndFunction::class,
  69.         'bit_or'    => Functions\BitOrFunction::class,
  70.         // Aggregate functions
  71.         'min'       => Functions\MinFunction::class,
  72.         'max'       => Functions\MaxFunction::class,
  73.         'avg'       => Functions\AvgFunction::class,
  74.         'sum'       => Functions\SumFunction::class,
  75.         'count'     => Functions\CountFunction::class,
  76.     ];
  77.     /**
  78.      * READ-ONLY: Maps BUILT-IN datetime function names to AST class names.
  79.      *
  80.      * @var array
  81.      *
  82.      * @psalm-var class-string<Functions\FunctionNode>
  83.      */
  84.     private static $_DATETIME_FUNCTIONS = [
  85.         'current_date'      => Functions\CurrentDateFunction::class,
  86.         'current_time'      => Functions\CurrentTimeFunction::class,
  87.         'current_timestamp' => Functions\CurrentTimestampFunction::class,
  88.         'date_add'          => Functions\DateAddFunction::class,
  89.         'date_sub'          => Functions\DateSubFunction::class,
  90.     ];
  91.     /*
  92.      * Expressions that were encountered during parsing of identifiers and expressions
  93.      * and still need to be validated.
  94.      */
  95.     /**
  96.      * @var array
  97.      */
  98.     private $deferredIdentificationVariables = [];
  99.     /**
  100.      * @var array
  101.      */
  102.     private $deferredPartialObjectExpressions = [];
  103.     /**
  104.      * @var array
  105.      */
  106.     private $deferredPathExpressions = [];
  107.     /**
  108.      * @var array
  109.      */
  110.     private $deferredResultVariables = [];
  111.     /**
  112.      * @var array
  113.      */
  114.     private $deferredNewObjectExpressions = [];
  115.     /**
  116.      * The lexer.
  117.      *
  118.      * @var \Doctrine\ORM\Query\Lexer
  119.      */
  120.     private $lexer;
  121.     /**
  122.      * The parser result.
  123.      *
  124.      * @var \Doctrine\ORM\Query\ParserResult
  125.      */
  126.     private $parserResult;
  127.     /**
  128.      * The EntityManager.
  129.      *
  130.      * @var \Doctrine\ORM\EntityManager
  131.      */
  132.     private $em;
  133.     /**
  134.      * The Query to parse.
  135.      *
  136.      * @var Query
  137.      */
  138.     private $query;
  139.     /**
  140.      * Map of declared query components in the parsed query.
  141.      *
  142.      * @var array
  143.      */
  144.     private $queryComponents = [];
  145.     /**
  146.      * Keeps the nesting level of defined ResultVariables.
  147.      *
  148.      * @var integer
  149.      */
  150.     private $nestingLevel 0;
  151.     /**
  152.      * Any additional custom tree walkers that modify the AST.
  153.      *
  154.      * @var array
  155.      */
  156.     private $customTreeWalkers = [];
  157.     /**
  158.      * The custom last tree walker, if any, that is responsible for producing the output.
  159.      *
  160.      * @var class-string<TreeWalker>
  161.      */
  162.     private $customOutputWalker;
  163.     /**
  164.      * @var array
  165.      */
  166.     private $identVariableExpressions = [];
  167.     /**
  168.      * Creates a new query parser object.
  169.      *
  170.      * @param Query $query The Query to parse.
  171.      */
  172.     public function __construct(Query $query)
  173.     {
  174.         $this->query        $query;
  175.         $this->em           $query->getEntityManager();
  176.         $this->lexer        = new Lexer((string) $query->getDQL());
  177.         $this->parserResult = new ParserResult();
  178.     }
  179.     /**
  180.      * Sets a custom tree walker that produces output.
  181.      * This tree walker will be run last over the AST, after any other walkers.
  182.      *
  183.      * @param string $className
  184.      *
  185.      * @return void
  186.      */
  187.     public function setCustomOutputTreeWalker($className)
  188.     {
  189.         $this->customOutputWalker $className;
  190.     }
  191.     /**
  192.      * Adds a custom tree walker for modifying the AST.
  193.      *
  194.      * @param string $className
  195.      *
  196.      * @return void
  197.      */
  198.     public function addCustomTreeWalker($className)
  199.     {
  200.         $this->customTreeWalkers[] = $className;
  201.     }
  202.     /**
  203.      * Gets the lexer used by the parser.
  204.      *
  205.      * @return \Doctrine\ORM\Query\Lexer
  206.      */
  207.     public function getLexer()
  208.     {
  209.         return $this->lexer;
  210.     }
  211.     /**
  212.      * Gets the ParserResult that is being filled with information during parsing.
  213.      *
  214.      * @return \Doctrine\ORM\Query\ParserResult
  215.      */
  216.     public function getParserResult()
  217.     {
  218.         return $this->parserResult;
  219.     }
  220.     /**
  221.      * Gets the EntityManager used by the parser.
  222.      *
  223.      * @return \Doctrine\ORM\EntityManager
  224.      */
  225.     public function getEntityManager()
  226.     {
  227.         return $this->em;
  228.     }
  229.     /**
  230.      * Parses and builds AST for the given Query.
  231.      *
  232.      * @return \Doctrine\ORM\Query\AST\SelectStatement |
  233.      *         \Doctrine\ORM\Query\AST\UpdateStatement |
  234.      *         \Doctrine\ORM\Query\AST\DeleteStatement
  235.      */
  236.     public function getAST()
  237.     {
  238.         // Parse & build AST
  239.         $AST $this->QueryLanguage();
  240.         // Process any deferred validations of some nodes in the AST.
  241.         // This also allows post-processing of the AST for modification purposes.
  242.         $this->processDeferredIdentificationVariables();
  243.         if ($this->deferredPartialObjectExpressions) {
  244.             $this->processDeferredPartialObjectExpressions();
  245.         }
  246.         if ($this->deferredPathExpressions) {
  247.             $this->processDeferredPathExpressions();
  248.         }
  249.         if ($this->deferredResultVariables) {
  250.             $this->processDeferredResultVariables();
  251.         }
  252.         if ($this->deferredNewObjectExpressions) {
  253.             $this->processDeferredNewObjectExpressions($AST);
  254.         }
  255.         $this->processRootEntityAliasSelected();
  256.         // TODO: Is there a way to remove this? It may impact the mixed hydration resultset a lot!
  257.         $this->fixIdentificationVariableOrder($AST);
  258.         return $AST;
  259.     }
  260.     /**
  261.      * Attempts to match the given token with the current lookahead token.
  262.      *
  263.      * If they match, updates the lookahead token; otherwise raises a syntax
  264.      * error.
  265.      *
  266.      * @param int $token The token type.
  267.      *
  268.      * @return void
  269.      *
  270.      * @throws QueryException If the tokens don't match.
  271.      */
  272.     public function match($token)
  273.     {
  274.         $lookaheadType $this->lexer->lookahead['type'] ?? null;
  275.         // Short-circuit on first condition, usually types match
  276.         if ($lookaheadType === $token) {
  277.             $this->lexer->moveNext();
  278.             return;
  279.         }
  280.         // If parameter is not identifier (1-99) must be exact match
  281.         if ($token Lexer::T_IDENTIFIER) {
  282.             $this->syntaxError($this->lexer->getLiteral($token));
  283.         }
  284.         // If parameter is keyword (200+) must be exact match
  285.         if ($token Lexer::T_IDENTIFIER) {
  286.             $this->syntaxError($this->lexer->getLiteral($token));
  287.         }
  288.         // If parameter is T_IDENTIFIER, then matches T_IDENTIFIER (100) and keywords (200+)
  289.         if ($token === Lexer::T_IDENTIFIER && $lookaheadType Lexer::T_IDENTIFIER) {
  290.             $this->syntaxError($this->lexer->getLiteral($token));
  291.         }
  292.         $this->lexer->moveNext();
  293.     }
  294.     /**
  295.      * Frees this parser, enabling it to be reused.
  296.      *
  297.      * @param boolean $deep     Whether to clean peek and reset errors.
  298.      * @param integer $position Position to reset.
  299.      *
  300.      * @return void
  301.      */
  302.     public function free($deep false$position 0)
  303.     {
  304.         // WARNING! Use this method with care. It resets the scanner!
  305.         $this->lexer->resetPosition($position);
  306.         // Deep = true cleans peek and also any previously defined errors
  307.         if ($deep) {
  308.             $this->lexer->resetPeek();
  309.         }
  310.         $this->lexer->token null;
  311.         $this->lexer->lookahead null;
  312.     }
  313.     /**
  314.      * Parses a query string.
  315.      *
  316.      * @return ParserResult
  317.      */
  318.     public function parse()
  319.     {
  320.         $AST $this->getAST();
  321.         if (($customWalkers $this->query->getHint(Query::HINT_CUSTOM_TREE_WALKERS)) !== false) {
  322.             $this->customTreeWalkers $customWalkers;
  323.         }
  324.         if (($customOutputWalker $this->query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER)) !== false) {
  325.             $this->customOutputWalker $customOutputWalker;
  326.         }
  327.         // Run any custom tree walkers over the AST
  328.         if ($this->customTreeWalkers) {
  329.             $treeWalkerChain = new TreeWalkerChain($this->query$this->parserResult$this->queryComponents);
  330.             foreach ($this->customTreeWalkers as $walker) {
  331.                 $treeWalkerChain->addTreeWalker($walker);
  332.             }
  333.             switch (true) {
  334.                 case ($AST instanceof AST\UpdateStatement):
  335.                     $treeWalkerChain->walkUpdateStatement($AST);
  336.                     break;
  337.                 case ($AST instanceof AST\DeleteStatement):
  338.                     $treeWalkerChain->walkDeleteStatement($AST);
  339.                     break;
  340.                 case ($AST instanceof AST\SelectStatement):
  341.                 default:
  342.                     $treeWalkerChain->walkSelectStatement($AST);
  343.             }
  344.             $this->queryComponents $treeWalkerChain->getQueryComponents();
  345.         }
  346.         $outputWalkerClass $this->customOutputWalker ?: SqlWalker::class;
  347.         $outputWalker      = new $outputWalkerClass($this->query$this->parserResult$this->queryComponents);
  348.         // Assign an SQL executor to the parser result
  349.         $this->parserResult->setSqlExecutor($outputWalker->getExecutor($AST));
  350.         return $this->parserResult;
  351.     }
  352.     /**
  353.      * Fixes order of identification variables.
  354.      *
  355.      * They have to appear in the select clause in the same order as the
  356.      * declarations (from ... x join ... y join ... z ...) appear in the query
  357.      * as the hydration process relies on that order for proper operation.
  358.      *
  359.      * @param AST\SelectStatement|AST\DeleteStatement|AST\UpdateStatement $AST
  360.      *
  361.      * @return void
  362.      */
  363.     private function fixIdentificationVariableOrder($AST)
  364.     {
  365.         if (count($this->identVariableExpressions) <= 1) {
  366.             return;
  367.         }
  368.         foreach ($this->queryComponents as $dqlAlias => $qComp) {
  369.             if ( ! isset($this->identVariableExpressions[$dqlAlias])) {
  370.                 continue;
  371.             }
  372.             $expr $this->identVariableExpressions[$dqlAlias];
  373.             $key  array_search($expr$AST->selectClause->selectExpressions);
  374.             unset($AST->selectClause->selectExpressions[$key]);
  375.             $AST->selectClause->selectExpressions[] = $expr;
  376.         }
  377.     }
  378.     /**
  379.      * Generates a new syntax error.
  380.      *
  381.      * @param string     $expected Expected string.
  382.      * @param array|null $token    Got token.
  383.      *
  384.      * @return void
  385.      *
  386.      * @throws \Doctrine\ORM\Query\QueryException
  387.      */
  388.     public function syntaxError($expected ''$token null)
  389.     {
  390.         if ($token === null) {
  391.             $token $this->lexer->lookahead;
  392.         }
  393.         $tokenPos = (isset($token['position'])) ? $token['position'] : '-1';
  394.         $message  "line 0, col {$tokenPos}: Error: ";
  395.         $message .= ($expected !== '') ? "Expected {$expected}, got " 'Unexpected ';
  396.         $message .= ($this->lexer->lookahead === null) ? 'end of string.' "'{$token['value']}'";
  397.         throw QueryException::syntaxError($messageQueryException::dqlError($this->query->getDQL()));
  398.     }
  399.     /**
  400.      * Generates a new semantical error.
  401.      *
  402.      * @param string     $message Optional message.
  403.      * @param array|null $token   Optional token.
  404.      *
  405.      * @return void
  406.      *
  407.      * @throws \Doctrine\ORM\Query\QueryException
  408.      */
  409.     public function semanticalError($message ''$token null)
  410.     {
  411.         if ($token === null) {
  412.             $token $this->lexer->lookahead ?? ['position' => null];
  413.         }
  414.         // Minimum exposed chars ahead of token
  415.         $distance 12;
  416.         // Find a position of a final word to display in error string
  417.         $dql    $this->query->getDQL();
  418.         $length strlen($dql);
  419.         $pos    $token['position'] + $distance;
  420.         $pos    strpos($dql' ', ($length $pos) ? $pos $length);
  421.         $length = ($pos !== false) ? $pos $token['position'] : $distance;
  422.         $tokenPos = (isset($token['position']) && $token['position'] > 0) ? $token['position'] : '-1';
  423.         $tokenStr substr($dql$token['position'], $length);
  424.         // Building informative message
  425.         $message 'line 0, col ' $tokenPos " near '" $tokenStr "': Error: " $message;
  426.         throw QueryException::semanticalError($messageQueryException::dqlError($this->query->getDQL()));
  427.     }
  428.     /**
  429.      * Peeks beyond the matched closing parenthesis and returns the first token after that one.
  430.      *
  431.      * @param boolean $resetPeek Reset peek after finding the closing parenthesis.
  432.      *
  433.      * @return array
  434.      */
  435.     private function peekBeyondClosingParenthesis($resetPeek true)
  436.     {
  437.         $token $this->lexer->peek();
  438.         $numUnmatched 1;
  439.         while ($numUnmatched && $token !== null) {
  440.             switch ($token['type']) {
  441.                 case Lexer::T_OPEN_PARENTHESIS:
  442.                     ++$numUnmatched;
  443.                     break;
  444.                 case Lexer::T_CLOSE_PARENTHESIS:
  445.                     --$numUnmatched;
  446.                     break;
  447.                 default:
  448.                     // Do nothing
  449.             }
  450.             $token $this->lexer->peek();
  451.         }
  452.         if ($resetPeek) {
  453.             $this->lexer->resetPeek();
  454.         }
  455.         return $token;
  456.     }
  457.     /**
  458.      * Checks if the given token indicates a mathematical operator.
  459.      *
  460.      * @param array $token
  461.      *
  462.      * @return boolean TRUE if the token is a mathematical operator, FALSE otherwise.
  463.      */
  464.     private function isMathOperator($token)
  465.     {
  466.         return $token !== null && in_array($token['type'], [Lexer::T_PLUSLexer::T_MINUSLexer::T_DIVIDELexer::T_MULTIPLY]);
  467.     }
  468.     /**
  469.      * Checks if the next-next (after lookahead) token starts a function.
  470.      *
  471.      * @return boolean TRUE if the next-next tokens start a function, FALSE otherwise.
  472.      */
  473.     private function isFunction()
  474.     {
  475.         $lookaheadType $this->lexer->lookahead['type'];
  476.         $peek          $this->lexer->peek();
  477.         $this->lexer->resetPeek();
  478.         return $lookaheadType >= Lexer::T_IDENTIFIER && $peek !== null && $peek['type'] === Lexer::T_OPEN_PARENTHESIS;
  479.     }
  480.     /**
  481.      * Checks whether the given token type indicates an aggregate function.
  482.      *
  483.      * @param int $tokenType
  484.      *
  485.      * @return boolean TRUE if the token type is an aggregate function, FALSE otherwise.
  486.      */
  487.     private function isAggregateFunction($tokenType)
  488.     {
  489.         return in_array($tokenType, [Lexer::T_AVGLexer::T_MINLexer::T_MAXLexer::T_SUMLexer::T_COUNT]);
  490.     }
  491.     /**
  492.      * Checks whether the current lookahead token of the lexer has the type T_ALL, T_ANY or T_SOME.
  493.      *
  494.      * @return boolean
  495.      */
  496.     private function isNextAllAnySome()
  497.     {
  498.         return in_array($this->lexer->lookahead['type'], [Lexer::T_ALLLexer::T_ANYLexer::T_SOME]);
  499.     }
  500.     /**
  501.      * Validates that the given <tt>IdentificationVariable</tt> is semantically correct.
  502.      * It must exist in query components list.
  503.      *
  504.      * @return void
  505.      */
  506.     private function processDeferredIdentificationVariables()
  507.     {
  508.         foreach ($this->deferredIdentificationVariables as $deferredItem) {
  509.             $identVariable $deferredItem['expression'];
  510.             // Check if IdentificationVariable exists in queryComponents
  511.             if ( ! isset($this->queryComponents[$identVariable])) {
  512.                 $this->semanticalError(
  513.                     "'$identVariable' is not defined."$deferredItem['token']
  514.                 );
  515.             }
  516.             $qComp $this->queryComponents[$identVariable];
  517.             // Check if queryComponent points to an AbstractSchemaName or a ResultVariable
  518.             if ( ! isset($qComp['metadata'])) {
  519.                 $this->semanticalError(
  520.                     "'$identVariable' does not point to a Class."$deferredItem['token']
  521.                 );
  522.             }
  523.             // Validate if identification variable nesting level is lower or equal than the current one
  524.             if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) {
  525.                 $this->semanticalError(
  526.                     "'$identVariable' is used outside the scope of its declaration."$deferredItem['token']
  527.                 );
  528.             }
  529.         }
  530.     }
  531.     /**
  532.      * Validates that the given <tt>NewObjectExpression</tt>.
  533.      *
  534.      * @param \Doctrine\ORM\Query\AST\SelectClause $AST
  535.      *
  536.      * @return void
  537.      */
  538.     private function processDeferredNewObjectExpressions($AST)
  539.     {
  540.         foreach ($this->deferredNewObjectExpressions as $deferredItem) {
  541.             $expression     $deferredItem['expression'];
  542.             $token          $deferredItem['token'];
  543.             $className      $expression->className;
  544.             $args           $expression->args;
  545.             $fromClassName  = isset($AST->fromClause->identificationVariableDeclarations[0]->rangeVariableDeclaration->abstractSchemaName)
  546.                 ? $AST->fromClause->identificationVariableDeclarations[0]->rangeVariableDeclaration->abstractSchemaName
  547.                 null;
  548.             // If the namespace is not given then assumes the first FROM entity namespace
  549.             if (strpos($className'\\') === false && ! class_exists($className) && strpos($fromClassName'\\') !== false) {
  550.                 $namespace  substr($fromClassName0strrpos($fromClassName'\\'));
  551.                 $fqcn       $namespace '\\' $className;
  552.                 if (class_exists($fqcn)) {
  553.                     $expression->className  $fqcn;
  554.                     $className              $fqcn;
  555.                 }
  556.             }
  557.             if ( ! class_exists($className)) {
  558.                 $this->semanticalError(sprintf('Class "%s" is not defined.'$className), $token);
  559.             }
  560.             $class = new \ReflectionClass($className);
  561.             if ( ! $class->isInstantiable()) {
  562.                 $this->semanticalError(sprintf('Class "%s" can not be instantiated.'$className), $token);
  563.             }
  564.             if ($class->getConstructor() === null) {
  565.                 $this->semanticalError(sprintf('Class "%s" has not a valid constructor.'$className), $token);
  566.             }
  567.             if ($class->getConstructor()->getNumberOfRequiredParameters() > count($args)) {
  568.                 $this->semanticalError(sprintf('Number of arguments does not match with "%s" constructor declaration.'$className), $token);
  569.             }
  570.         }
  571.     }
  572.     /**
  573.      * Validates that the given <tt>PartialObjectExpression</tt> is semantically correct.
  574.      * It must exist in query components list.
  575.      *
  576.      * @return void
  577.      */
  578.     private function processDeferredPartialObjectExpressions()
  579.     {
  580.         foreach ($this->deferredPartialObjectExpressions as $deferredItem) {
  581.             $expr $deferredItem['expression'];
  582.             $class $this->queryComponents[$expr->identificationVariable]['metadata'];
  583.             foreach ($expr->partialFieldSet as $field) {
  584.                 if (isset($class->fieldMappings[$field])) {
  585.                     continue;
  586.                 }
  587.                 if (isset($class->associationMappings[$field]) &&
  588.                     $class->associationMappings[$field]['isOwningSide'] &&
  589.                     $class->associationMappings[$field]['type'] & ClassMetadata::TO_ONE) {
  590.                     continue;
  591.                 }
  592.                 $this->semanticalError(
  593.                     "There is no mapped field named '$field' on class " $class->name "."$deferredItem['token']
  594.                 );
  595.             }
  596.             if (array_intersect($class->identifier$expr->partialFieldSet) != $class->identifier) {
  597.                 $this->semanticalError(
  598.                     "The partial field selection of class " $class->name " must contain the identifier.",
  599.                     $deferredItem['token']
  600.                 );
  601.             }
  602.         }
  603.     }
  604.     /**
  605.      * Validates that the given <tt>ResultVariable</tt> is semantically correct.
  606.      * It must exist in query components list.
  607.      *
  608.      * @return void
  609.      */
  610.     private function processDeferredResultVariables()
  611.     {
  612.         foreach ($this->deferredResultVariables as $deferredItem) {
  613.             $resultVariable $deferredItem['expression'];
  614.             // Check if ResultVariable exists in queryComponents
  615.             if ( ! isset($this->queryComponents[$resultVariable])) {
  616.                 $this->semanticalError(
  617.                     "'$resultVariable' is not defined."$deferredItem['token']
  618.                 );
  619.             }
  620.             $qComp $this->queryComponents[$resultVariable];
  621.             // Check if queryComponent points to an AbstractSchemaName or a ResultVariable
  622.             if ( ! isset($qComp['resultVariable'])) {
  623.                 $this->semanticalError(
  624.                     "'$resultVariable' does not point to a ResultVariable."$deferredItem['token']
  625.                 );
  626.             }
  627.             // Validate if identification variable nesting level is lower or equal than the current one
  628.             if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) {
  629.                 $this->semanticalError(
  630.                     "'$resultVariable' is used outside the scope of its declaration."$deferredItem['token']
  631.                 );
  632.             }
  633.         }
  634.     }
  635.     /**
  636.      * Validates that the given <tt>PathExpression</tt> is semantically correct for grammar rules:
  637.      *
  638.      * AssociationPathExpression             ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
  639.      * SingleValuedPathExpression            ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
  640.      * StateFieldPathExpression              ::= IdentificationVariable "." StateField
  641.      * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
  642.      * CollectionValuedPathExpression        ::= IdentificationVariable "." CollectionValuedAssociationField
  643.      *
  644.      * @return void
  645.      */
  646.     private function processDeferredPathExpressions()
  647.     {
  648.         foreach ($this->deferredPathExpressions as $deferredItem) {
  649.             $pathExpression $deferredItem['expression'];
  650.             $qComp $this->queryComponents[$pathExpression->identificationVariable];
  651.             $class $qComp['metadata'];
  652.             if (($field $pathExpression->field) === null) {
  653.                 $field $pathExpression->field $class->identifier[0];
  654.             }
  655.             // Check if field or association exists
  656.             if ( ! isset($class->associationMappings[$field]) && ! isset($class->fieldMappings[$field])) {
  657.                 $this->semanticalError(
  658.                     'Class ' $class->name ' has no field or association named ' $field,
  659.                     $deferredItem['token']
  660.                 );
  661.             }
  662.             $fieldType AST\PathExpression::TYPE_STATE_FIELD;
  663.             if (isset($class->associationMappings[$field])) {
  664.                 $assoc $class->associationMappings[$field];
  665.                 $fieldType = ($assoc['type'] & ClassMetadata::TO_ONE)
  666.                     ? AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION
  667.                     AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION;
  668.             }
  669.             // Validate if PathExpression is one of the expected types
  670.             $expectedType $pathExpression->expectedType;
  671.             if ( ! ($expectedType $fieldType)) {
  672.                 // We need to recognize which was expected type(s)
  673.                 $expectedStringTypes = [];
  674.                 // Validate state field type
  675.                 if ($expectedType AST\PathExpression::TYPE_STATE_FIELD) {
  676.                     $expectedStringTypes[] = 'StateFieldPathExpression';
  677.                 }
  678.                 // Validate single valued association (*-to-one)
  679.                 if ($expectedType AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION) {
  680.                     $expectedStringTypes[] = 'SingleValuedAssociationField';
  681.                 }
  682.                 // Validate single valued association (*-to-many)
  683.                 if ($expectedType AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION) {
  684.                     $expectedStringTypes[] = 'CollectionValuedAssociationField';
  685.                 }
  686.                 // Build the error message
  687.                 $semanticalError  'Invalid PathExpression. ';
  688.                 $semanticalError .= (count($expectedStringTypes) == 1)
  689.                     ? 'Must be a ' $expectedStringTypes[0] . '.'
  690.                     implode(' or '$expectedStringTypes) . ' expected.';
  691.                 $this->semanticalError($semanticalError$deferredItem['token']);
  692.             }
  693.             // We need to force the type in PathExpression
  694.             $pathExpression->type $fieldType;
  695.         }
  696.     }
  697.     /**
  698.      * @return void
  699.      */
  700.     private function processRootEntityAliasSelected()
  701.     {
  702.         if ( ! count($this->identVariableExpressions)) {
  703.             return;
  704.         }
  705.         foreach ($this->identVariableExpressions as $dqlAlias => $expr) {
  706.             if (isset($this->queryComponents[$dqlAlias]) && $this->queryComponents[$dqlAlias]['parent'] === null) {
  707.                 return;
  708.             }
  709.         }
  710.         $this->semanticalError('Cannot select entity through identification variables without choosing at least one root entity alias.');
  711.     }
  712.     /**
  713.      * QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
  714.      *
  715.      * @return \Doctrine\ORM\Query\AST\SelectStatement |
  716.      *         \Doctrine\ORM\Query\AST\UpdateStatement |
  717.      *         \Doctrine\ORM\Query\AST\DeleteStatement
  718.      */
  719.     public function QueryLanguage()
  720.     {
  721.         $statement null;
  722.         $this->lexer->moveNext();
  723.         switch ($this->lexer->lookahead['type'] ?? null) {
  724.             case Lexer::T_SELECT:
  725.                 $statement $this->SelectStatement();
  726.                 break;
  727.             case Lexer::T_UPDATE:
  728.                 $statement $this->UpdateStatement();
  729.                 break;
  730.             case Lexer::T_DELETE:
  731.                 $statement $this->DeleteStatement();
  732.                 break;
  733.             default:
  734.                 $this->syntaxError('SELECT, UPDATE or DELETE');
  735.                 break;
  736.         }
  737.         // Check for end of string
  738.         if ($this->lexer->lookahead !== null) {
  739.             $this->syntaxError('end of string');
  740.         }
  741.         return $statement;
  742.     }
  743.     /**
  744.      * SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
  745.      *
  746.      * @return \Doctrine\ORM\Query\AST\SelectStatement
  747.      */
  748.     public function SelectStatement()
  749.     {
  750.         $selectStatement = new AST\SelectStatement($this->SelectClause(), $this->FromClause());
  751.         $selectStatement->whereClause   $this->lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null;
  752.         $selectStatement->groupByClause $this->lexer->isNextToken(Lexer::T_GROUP) ? $this->GroupByClause() : null;
  753.         $selectStatement->havingClause  $this->lexer->isNextToken(Lexer::T_HAVING) ? $this->HavingClause() : null;
  754.         $selectStatement->orderByClause $this->lexer->isNextToken(Lexer::T_ORDER) ? $this->OrderByClause() : null;
  755.         return $selectStatement;
  756.     }
  757.     /**
  758.      * UpdateStatement ::= UpdateClause [WhereClause]
  759.      *
  760.      * @return \Doctrine\ORM\Query\AST\UpdateStatement
  761.      */
  762.     public function UpdateStatement()
  763.     {
  764.         $updateStatement = new AST\UpdateStatement($this->UpdateClause());
  765.         $updateStatement->whereClause $this->lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null;
  766.         return $updateStatement;
  767.     }
  768.     /**
  769.      * DeleteStatement ::= DeleteClause [WhereClause]
  770.      *
  771.      * @return \Doctrine\ORM\Query\AST\DeleteStatement
  772.      */
  773.     public function DeleteStatement()
  774.     {
  775.         $deleteStatement = new AST\DeleteStatement($this->DeleteClause());
  776.         $deleteStatement->whereClause $this->lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null;
  777.         return $deleteStatement;
  778.     }
  779.     /**
  780.      * IdentificationVariable ::= identifier
  781.      *
  782.      * @return string
  783.      */
  784.     public function IdentificationVariable()
  785.     {
  786.         $this->match(Lexer::T_IDENTIFIER);
  787.         $identVariable $this->lexer->token['value'];
  788.         $this->deferredIdentificationVariables[] = [
  789.             'expression'   => $identVariable,
  790.             'nestingLevel' => $this->nestingLevel,
  791.             'token'        => $this->lexer->token,
  792.         ];
  793.         return $identVariable;
  794.     }
  795.     /**
  796.      * AliasIdentificationVariable = identifier
  797.      *
  798.      * @return string
  799.      */
  800.     public function AliasIdentificationVariable()
  801.     {
  802.         $this->match(Lexer::T_IDENTIFIER);
  803.         $aliasIdentVariable $this->lexer->token['value'];
  804.         $exists = isset($this->queryComponents[$aliasIdentVariable]);
  805.         if ($exists) {
  806.             $this->semanticalError("'$aliasIdentVariable' is already defined."$this->lexer->token);
  807.         }
  808.         return $aliasIdentVariable;
  809.     }
  810.     /**
  811.      * AbstractSchemaName ::= fully_qualified_name | aliased_name | identifier
  812.      *
  813.      * @return string
  814.      */
  815.     public function AbstractSchemaName()
  816.     {
  817.         if ($this->lexer->isNextToken(Lexer::T_FULLY_QUALIFIED_NAME)) {
  818.             $this->match(Lexer::T_FULLY_QUALIFIED_NAME);
  819.             return $this->lexer->token['value'];
  820.         }
  821.         if ($this->lexer->isNextToken(Lexer::T_IDENTIFIER)) {
  822.             $this->match(Lexer::T_IDENTIFIER);
  823.             return $this->lexer->token['value'];
  824.         }
  825.         $this->match(Lexer::T_ALIASED_NAME);
  826.         [$namespaceAlias$simpleClassName] = explode(':'$this->lexer->token['value']);
  827.         return $this->em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' $simpleClassName;
  828.     }
  829.     /**
  830.      * Validates an AbstractSchemaName, making sure the class exists.
  831.      *
  832.      * @param string $schemaName The name to validate.
  833.      *
  834.      * @throws QueryException if the name does not exist.
  835.      */
  836.     private function validateAbstractSchemaName($schemaName)
  837.     {
  838.         if (! (class_exists($schemaNametrue) || interface_exists($schemaNametrue))) {
  839.             $this->semanticalError("Class '$schemaName' is not defined."$this->lexer->token);
  840.         }
  841.     }
  842.     /**
  843.      * AliasResultVariable ::= identifier
  844.      *
  845.      * @return string
  846.      */
  847.     public function AliasResultVariable()
  848.     {
  849.         $this->match(Lexer::T_IDENTIFIER);
  850.         $resultVariable $this->lexer->token['value'];
  851.         $exists = isset($this->queryComponents[$resultVariable]);
  852.         if ($exists) {
  853.             $this->semanticalError("'$resultVariable' is already defined."$this->lexer->token);
  854.         }
  855.         return $resultVariable;
  856.     }
  857.     /**
  858.      * ResultVariable ::= identifier
  859.      *
  860.      * @return string
  861.      */
  862.     public function ResultVariable()
  863.     {
  864.         $this->match(Lexer::T_IDENTIFIER);
  865.         $resultVariable $this->lexer->token['value'];
  866.         // Defer ResultVariable validation
  867.         $this->deferredResultVariables[] = [
  868.             'expression'   => $resultVariable,
  869.             'nestingLevel' => $this->nestingLevel,
  870.             'token'        => $this->lexer->token,
  871.         ];
  872.         return $resultVariable;
  873.     }
  874.     /**
  875.      * JoinAssociationPathExpression ::= IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField)
  876.      *
  877.      * @return \Doctrine\ORM\Query\AST\JoinAssociationPathExpression
  878.      */
  879.     public function JoinAssociationPathExpression()
  880.     {
  881.         $identVariable $this->IdentificationVariable();
  882.         if ( ! isset($this->queryComponents[$identVariable])) {
  883.             $this->semanticalError(
  884.                 'Identification Variable ' $identVariable .' used in join path expression but was not defined before.'
  885.             );
  886.         }
  887.         $this->match(Lexer::T_DOT);
  888.         $this->match(Lexer::T_IDENTIFIER);
  889.         $field $this->lexer->token['value'];
  890.         // Validate association field
  891.         $qComp $this->queryComponents[$identVariable];
  892.         $class $qComp['metadata'];
  893.         if ( ! $class->hasAssociation($field)) {
  894.             $this->semanticalError('Class ' $class->name ' has no association named ' $field);
  895.         }
  896.         return new AST\JoinAssociationPathExpression($identVariable$field);
  897.     }
  898.     /**
  899.      * Parses an arbitrary path expression and defers semantical validation
  900.      * based on expected types.
  901.      *
  902.      * PathExpression ::= IdentificationVariable {"." identifier}*
  903.      *
  904.      * @param integer $expectedTypes
  905.      *
  906.      * @return \Doctrine\ORM\Query\AST\PathExpression
  907.      */
  908.     public function PathExpression($expectedTypes)
  909.     {
  910.         $identVariable $this->IdentificationVariable();
  911.         $field null;
  912.         if ($this->lexer->isNextToken(Lexer::T_DOT)) {
  913.             $this->match(Lexer::T_DOT);
  914.             $this->match(Lexer::T_IDENTIFIER);
  915.             $field $this->lexer->token['value'];
  916.             while ($this->lexer->isNextToken(Lexer::T_DOT)) {
  917.                 $this->match(Lexer::T_DOT);
  918.                 $this->match(Lexer::T_IDENTIFIER);
  919.                 $field .= '.'.$this->lexer->token['value'];
  920.             }
  921.         }
  922.         // Creating AST node
  923.         $pathExpr = new AST\PathExpression($expectedTypes$identVariable$field);
  924.         // Defer PathExpression validation if requested to be deferred
  925.         $this->deferredPathExpressions[] = [
  926.             'expression'   => $pathExpr,
  927.             'nestingLevel' => $this->nestingLevel,
  928.             'token'        => $this->lexer->token,
  929.         ];
  930.         return $pathExpr;
  931.     }
  932.     /**
  933.      * AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
  934.      *
  935.      * @return \Doctrine\ORM\Query\AST\PathExpression
  936.      */
  937.     public function AssociationPathExpression()
  938.     {
  939.         return $this->PathExpression(
  940.             AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION |
  941.             AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION
  942.         );
  943.     }
  944.     /**
  945.      * SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
  946.      *
  947.      * @return \Doctrine\ORM\Query\AST\PathExpression
  948.      */
  949.     public function SingleValuedPathExpression()
  950.     {
  951.         return $this->PathExpression(
  952.             AST\PathExpression::TYPE_STATE_FIELD |
  953.             AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION
  954.         );
  955.     }
  956.     /**
  957.      * StateFieldPathExpression ::= IdentificationVariable "." StateField
  958.      *
  959.      * @return \Doctrine\ORM\Query\AST\PathExpression
  960.      */
  961.     public function StateFieldPathExpression()
  962.     {
  963.         return $this->PathExpression(AST\PathExpression::TYPE_STATE_FIELD);
  964.     }
  965.     /**
  966.      * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
  967.      *
  968.      * @return \Doctrine\ORM\Query\AST\PathExpression
  969.      */
  970.     public function SingleValuedAssociationPathExpression()
  971.     {
  972.         return $this->PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION);
  973.     }
  974.     /**
  975.      * CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField
  976.      *
  977.      * @return \Doctrine\ORM\Query\AST\PathExpression
  978.      */
  979.     public function CollectionValuedPathExpression()
  980.     {
  981.         return $this->PathExpression(AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION);
  982.     }
  983.     /**
  984.      * SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}
  985.      *
  986.      * @return \Doctrine\ORM\Query\AST\SelectClause
  987.      */
  988.     public function SelectClause()
  989.     {
  990.         $isDistinct false;
  991.         $this->match(Lexer::T_SELECT);
  992.         // Check for DISTINCT
  993.         if ($this->lexer->isNextToken(Lexer::T_DISTINCT)) {
  994.             $this->match(Lexer::T_DISTINCT);
  995.             $isDistinct true;
  996.         }
  997.         // Process SelectExpressions (1..N)
  998.         $selectExpressions = [];
  999.         $selectExpressions[] = $this->SelectExpression();
  1000.         while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
  1001.             $this->match(Lexer::T_COMMA);
  1002.             $selectExpressions[] = $this->SelectExpression();
  1003.         }
  1004.         return new AST\SelectClause($selectExpressions$isDistinct);
  1005.     }
  1006.     /**
  1007.      * SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression
  1008.      *
  1009.      * @return \Doctrine\ORM\Query\AST\SimpleSelectClause
  1010.      */
  1011.     public function SimpleSelectClause()
  1012.     {
  1013.         $isDistinct false;
  1014.         $this->match(Lexer::T_SELECT);
  1015.         if ($this->lexer->isNextToken(Lexer::T_DISTINCT)) {
  1016.             $this->match(Lexer::T_DISTINCT);
  1017.             $isDistinct true;
  1018.         }
  1019.         return new AST\SimpleSelectClause($this->SimpleSelectExpression(), $isDistinct);
  1020.     }
  1021.     /**
  1022.      * UpdateClause ::= "UPDATE" AbstractSchemaName ["AS"] AliasIdentificationVariable "SET" UpdateItem {"," UpdateItem}*
  1023.      *
  1024.      * @return \Doctrine\ORM\Query\AST\UpdateClause
  1025.      */
  1026.     public function UpdateClause()
  1027.     {
  1028.         $this->match(Lexer::T_UPDATE);
  1029.         $token $this->lexer->lookahead;
  1030.         $abstractSchemaName $this->AbstractSchemaName();
  1031.         $this->validateAbstractSchemaName($abstractSchemaName);
  1032.         if ($this->lexer->isNextToken(Lexer::T_AS)) {
  1033.             $this->match(Lexer::T_AS);
  1034.         }
  1035.         $aliasIdentificationVariable $this->AliasIdentificationVariable();
  1036.         $class $this->em->getClassMetadata($abstractSchemaName);
  1037.         // Building queryComponent
  1038.         $queryComponent = [
  1039.             'metadata'     => $class,
  1040.             'parent'       => null,
  1041.             'relation'     => null,
  1042.             'map'          => null,
  1043.             'nestingLevel' => $this->nestingLevel,
  1044.             'token'        => $token,
  1045.         ];
  1046.         $this->queryComponents[$aliasIdentificationVariable] = $queryComponent;
  1047.         $this->match(Lexer::T_SET);
  1048.         $updateItems = [];
  1049.         $updateItems[] = $this->UpdateItem();
  1050.         while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
  1051.             $this->match(Lexer::T_COMMA);
  1052.             $updateItems[] = $this->UpdateItem();
  1053.         }
  1054.         $updateClause = new AST\UpdateClause($abstractSchemaName$updateItems);
  1055.         $updateClause->aliasIdentificationVariable $aliasIdentificationVariable;
  1056.         return $updateClause;
  1057.     }
  1058.     /**
  1059.      * DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName ["AS"] AliasIdentificationVariable
  1060.      *
  1061.      * @return \Doctrine\ORM\Query\AST\DeleteClause
  1062.      */
  1063.     public function DeleteClause()
  1064.     {
  1065.         $this->match(Lexer::T_DELETE);
  1066.         if ($this->lexer->isNextToken(Lexer::T_FROM)) {
  1067.             $this->match(Lexer::T_FROM);
  1068.         }
  1069.         $token $this->lexer->lookahead;
  1070.         $abstractSchemaName $this->AbstractSchemaName();
  1071.         $this->validateAbstractSchemaName($abstractSchemaName);
  1072.         $deleteClause = new AST\DeleteClause($abstractSchemaName);
  1073.         if ($this->lexer->isNextToken(Lexer::T_AS)) {
  1074.             $this->match(Lexer::T_AS);
  1075.         }
  1076.         $aliasIdentificationVariable $this->lexer->isNextToken(Lexer::T_IDENTIFIER)
  1077.             ? $this->AliasIdentificationVariable()
  1078.             : 'alias_should_have_been_set';
  1079.         $deleteClause->aliasIdentificationVariable $aliasIdentificationVariable;
  1080.         $class $this->em->getClassMetadata($deleteClause->abstractSchemaName);
  1081.         // Building queryComponent
  1082.         $queryComponent = [
  1083.             'metadata'     => $class,
  1084.             'parent'       => null,
  1085.             'relation'     => null,
  1086.             'map'          => null,
  1087.             'nestingLevel' => $this->nestingLevel,
  1088.             'token'        => $token,
  1089.         ];
  1090.         $this->queryComponents[$aliasIdentificationVariable] = $queryComponent;
  1091.         return $deleteClause;
  1092.     }
  1093.     /**
  1094.      * FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}*
  1095.      *
  1096.      * @return \Doctrine\ORM\Query\AST\FromClause
  1097.      */
  1098.     public function FromClause()
  1099.     {
  1100.         $this->match(Lexer::T_FROM);
  1101.         $identificationVariableDeclarations = [];
  1102.         $identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration();
  1103.         while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
  1104.             $this->match(Lexer::T_COMMA);
  1105.             $identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration();
  1106.         }
  1107.         return new AST\FromClause($identificationVariableDeclarations);
  1108.     }
  1109.     /**
  1110.      * SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}*
  1111.      *
  1112.      * @return \Doctrine\ORM\Query\AST\SubselectFromClause
  1113.      */
  1114.     public function SubselectFromClause()
  1115.     {
  1116.         $this->match(Lexer::T_FROM);
  1117.         $identificationVariables = [];
  1118.         $identificationVariables[] = $this->SubselectIdentificationVariableDeclaration();
  1119.         while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
  1120.             $this->match(Lexer::T_COMMA);
  1121.             $identificationVariables[] = $this->SubselectIdentificationVariableDeclaration();
  1122.         }
  1123.         return new AST\SubselectFromClause($identificationVariables);
  1124.     }
  1125.     /**
  1126.      * WhereClause ::= "WHERE" ConditionalExpression
  1127.      *
  1128.      * @return \Doctrine\ORM\Query\AST\WhereClause
  1129.      */
  1130.     public function WhereClause()
  1131.     {
  1132.         $this->match(Lexer::T_WHERE);
  1133.         return new AST\WhereClause($this->ConditionalExpression());
  1134.     }
  1135.     /**
  1136.      * HavingClause ::= "HAVING" ConditionalExpression
  1137.      *
  1138.      * @return \Doctrine\ORM\Query\AST\HavingClause
  1139.      */
  1140.     public function HavingClause()
  1141.     {
  1142.         $this->match(Lexer::T_HAVING);
  1143.         return new AST\HavingClause($this->ConditionalExpression());
  1144.     }
  1145.     /**
  1146.      * GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}*
  1147.      *
  1148.      * @return \Doctrine\ORM\Query\AST\GroupByClause
  1149.      */
  1150.     public function GroupByClause()
  1151.     {
  1152.         $this->match(Lexer::T_GROUP);
  1153.         $this->match(Lexer::T_BY);
  1154.         $groupByItems = [$this->GroupByItem()];
  1155.         while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
  1156.             $this->match(Lexer::T_COMMA);
  1157.             $groupByItems[] = $this->GroupByItem();
  1158.         }
  1159.         return new AST\GroupByClause($groupByItems);
  1160.     }
  1161.     /**
  1162.      * OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*
  1163.      *
  1164.      * @return \Doctrine\ORM\Query\AST\OrderByClause
  1165.      */
  1166.     public function OrderByClause()
  1167.     {
  1168.         $this->match(Lexer::T_ORDER);
  1169.         $this->match(Lexer::T_BY);
  1170.         $orderByItems = [];
  1171.         $orderByItems[] = $this->OrderByItem();
  1172.         while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
  1173.             $this->match(Lexer::T_COMMA);
  1174.             $orderByItems[] = $this->OrderByItem();
  1175.         }
  1176.         return new AST\OrderByClause($orderByItems);
  1177.     }
  1178.     /**
  1179.      * Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
  1180.      *
  1181.      * @return \Doctrine\ORM\Query\AST\Subselect
  1182.      */
  1183.     public function Subselect()
  1184.     {
  1185.         // Increase query nesting level
  1186.         $this->nestingLevel++;
  1187.         $subselect = new AST\Subselect($this->SimpleSelectClause(), $this->SubselectFromClause());
  1188.         $subselect->whereClause   $this->lexer->isNextToken(Lexer::T_WHERE) ? $this->WhereClause() : null;
  1189.         $subselect->groupByClause $this->lexer->isNextToken(Lexer::T_GROUP) ? $this->GroupByClause() : null;
  1190.         $subselect->havingClause  $this->lexer->isNextToken(Lexer::T_HAVING) ? $this->HavingClause() : null;
  1191.         $subselect->orderByClause $this->lexer->isNextToken(Lexer::T_ORDER) ? $this->OrderByClause() : null;
  1192.         // Decrease query nesting level
  1193.         $this->nestingLevel--;
  1194.         return $subselect;
  1195.     }
  1196.     /**
  1197.      * UpdateItem ::= SingleValuedPathExpression "=" NewValue
  1198.      *
  1199.      * @return \Doctrine\ORM\Query\AST\UpdateItem
  1200.      */
  1201.     public function UpdateItem()
  1202.     {
  1203.         $pathExpr $this->SingleValuedPathExpression();
  1204.         $this->match(Lexer::T_EQUALS);
  1205.         $updateItem = new AST\UpdateItem($pathExpr$this->NewValue());
  1206.         return $updateItem;
  1207.     }
  1208.     /**
  1209.      * GroupByItem ::= IdentificationVariable | ResultVariable | SingleValuedPathExpression
  1210.      *
  1211.      * @return string | \Doctrine\ORM\Query\AST\PathExpression
  1212.      */
  1213.     public function GroupByItem()
  1214.     {
  1215.         // We need to check if we are in a IdentificationVariable or SingleValuedPathExpression
  1216.         $glimpse $this->lexer->glimpse();
  1217.         if ($glimpse !== null && $glimpse['type'] === Lexer::T_DOT) {
  1218.             return $this->SingleValuedPathExpression();
  1219.         }
  1220.         // Still need to decide between IdentificationVariable or ResultVariable
  1221.         $lookaheadValue $this->lexer->lookahead['value'];
  1222.         if ( ! isset($this->queryComponents[$lookaheadValue])) {
  1223.             $this->semanticalError('Cannot group by undefined identification or result variable.');
  1224.         }
  1225.         return (isset($this->queryComponents[$lookaheadValue]['metadata']))
  1226.             ? $this->IdentificationVariable()
  1227.             : $this->ResultVariable();
  1228.     }
  1229.     /**
  1230.      * OrderByItem ::= (
  1231.      *      SimpleArithmeticExpression | SingleValuedPathExpression |
  1232.      *      ScalarExpression | ResultVariable | FunctionDeclaration
  1233.      * ) ["ASC" | "DESC"]
  1234.      *
  1235.      * @return \Doctrine\ORM\Query\AST\OrderByItem
  1236.      */
  1237.     public function OrderByItem()
  1238.     {
  1239.         $this->lexer->peek(); // lookahead => '.'
  1240.         $this->lexer->peek(); // lookahead => token after '.'
  1241.         $peek $this->lexer->peek(); // lookahead => token after the token after the '.'
  1242.         $this->lexer->resetPeek();
  1243.         $glimpse $this->lexer->glimpse();
  1244.         switch (true) {
  1245.             case ($this->isFunction()):
  1246.                 $expr $this->FunctionDeclaration();
  1247.                 break;
  1248.             case ($this->isMathOperator($peek)):
  1249.                 $expr $this->SimpleArithmeticExpression();
  1250.                 break;
  1251.             case $glimpse !== null && $glimpse['type'] === Lexer::T_DOT:
  1252.                 $expr $this->SingleValuedPathExpression();
  1253.                 break;
  1254.             case ($this->lexer->peek() && $this->isMathOperator($this->peekBeyondClosingParenthesis())):
  1255.                 $expr $this->ScalarExpression();
  1256.                 break;
  1257.             default:
  1258.                 $expr $this->ResultVariable();
  1259.                 break;
  1260.         }
  1261.         $type 'ASC';
  1262.         $item = new AST\OrderByItem($expr);
  1263.         switch (true) {
  1264.             case ($this->lexer->isNextToken(Lexer::T_DESC)):
  1265.                 $this->match(Lexer::T_DESC);
  1266.                 $type 'DESC';
  1267.                 break;
  1268.             case ($this->lexer->isNextToken(Lexer::T_ASC)):
  1269.                 $this->match(Lexer::T_ASC);
  1270.                 break;
  1271.             default:
  1272.                 // Do nothing
  1273.         }
  1274.         $item->type $type;
  1275.         return $item;
  1276.     }
  1277.     /**
  1278.      * NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary |
  1279.      *      EnumPrimary | SimpleEntityExpression | "NULL"
  1280.      *
  1281.      * NOTE: Since it is not possible to correctly recognize individual types, here is the full
  1282.      * grammar that needs to be supported:
  1283.      *
  1284.      * NewValue ::= SimpleArithmeticExpression | "NULL"
  1285.      *
  1286.      * SimpleArithmeticExpression covers all *Primary grammar rules and also SimpleEntityExpression
  1287.      *
  1288.      * @return AST\ArithmeticExpression
  1289.      */
  1290.     public function NewValue()
  1291.     {
  1292.         if ($this->lexer->isNextToken(Lexer::T_NULL)) {
  1293.             $this->match(Lexer::T_NULL);
  1294.             return null;
  1295.         }
  1296.         if ($this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
  1297.             $this->match(Lexer::T_INPUT_PARAMETER);
  1298.             return new AST\InputParameter($this->lexer->token['value']);
  1299.         }
  1300.         return $this->ArithmeticExpression();
  1301.     }
  1302.     /**
  1303.      * IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {Join}*
  1304.      *
  1305.      * @return \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration
  1306.      */
  1307.     public function IdentificationVariableDeclaration()
  1308.     {
  1309.         $joins                    = [];
  1310.         $rangeVariableDeclaration $this->RangeVariableDeclaration();
  1311.         $indexBy                  $this->lexer->isNextToken(Lexer::T_INDEX)
  1312.             ? $this->IndexBy()
  1313.             : null;
  1314.         $rangeVariableDeclaration->isRoot true;
  1315.         while (
  1316.             $this->lexer->isNextToken(Lexer::T_LEFT) ||
  1317.             $this->lexer->isNextToken(Lexer::T_INNER) ||
  1318.             $this->lexer->isNextToken(Lexer::T_JOIN)
  1319.         ) {
  1320.             $joins[] = $this->Join();
  1321.         }
  1322.         return new AST\IdentificationVariableDeclaration(
  1323.             $rangeVariableDeclaration$indexBy$joins
  1324.         );
  1325.     }
  1326.     /**
  1327.      * SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration
  1328.      *
  1329.      * {Internal note: WARNING: Solution is harder than a bare implementation.
  1330.      * Desired EBNF support:
  1331.      *
  1332.      * SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable)
  1333.      *
  1334.      * It demands that entire SQL generation to become programmatical. This is
  1335.      * needed because association based subselect requires "WHERE" conditional
  1336.      * expressions to be injected, but there is no scope to do that. Only scope
  1337.      * accessible is "FROM", prohibiting an easy implementation without larger
  1338.      * changes.}
  1339.      *
  1340.      * @return \Doctrine\ORM\Query\AST\SubselectIdentificationVariableDeclaration |
  1341.      *         \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration
  1342.      */
  1343.     public function SubselectIdentificationVariableDeclaration()
  1344.     {
  1345.         /*
  1346.         NOT YET IMPLEMENTED!
  1347.         $glimpse = $this->lexer->glimpse();
  1348.         if ($glimpse['type'] == Lexer::T_DOT) {
  1349.             $associationPathExpression = $this->AssociationPathExpression();
  1350.             if ($this->lexer->isNextToken(Lexer::T_AS)) {
  1351.                 $this->match(Lexer::T_AS);
  1352.             }
  1353.             $aliasIdentificationVariable = $this->AliasIdentificationVariable();
  1354.             $identificationVariable      = $associationPathExpression->identificationVariable;
  1355.             $field                       = $associationPathExpression->associationField;
  1356.             $class       = $this->queryComponents[$identificationVariable]['metadata'];
  1357.             $targetClass = $this->em->getClassMetadata($class->associationMappings[$field]['targetEntity']);
  1358.             // Building queryComponent
  1359.             $joinQueryComponent = array(
  1360.                 'metadata'     => $targetClass,
  1361.                 'parent'       => $identificationVariable,
  1362.                 'relation'     => $class->getAssociationMapping($field),
  1363.                 'map'          => null,
  1364.                 'nestingLevel' => $this->nestingLevel,
  1365.                 'token'        => $this->lexer->lookahead
  1366.             );
  1367.             $this->queryComponents[$aliasIdentificationVariable] = $joinQueryComponent;
  1368.             return new AST\SubselectIdentificationVariableDeclaration(
  1369.                 $associationPathExpression, $aliasIdentificationVariable
  1370.             );
  1371.         }
  1372.         */
  1373.         return $this->IdentificationVariableDeclaration();
  1374.     }
  1375.     /**
  1376.      * Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN"
  1377.      *          (JoinAssociationDeclaration | RangeVariableDeclaration)
  1378.      *          ["WITH" ConditionalExpression]
  1379.      *
  1380.      * @return \Doctrine\ORM\Query\AST\Join
  1381.      */
  1382.     public function Join()
  1383.     {
  1384.         // Check Join type
  1385.         $joinType AST\Join::JOIN_TYPE_INNER;
  1386.         switch (true) {
  1387.             case ($this->lexer->isNextToken(Lexer::T_LEFT)):
  1388.                 $this->match(Lexer::T_LEFT);
  1389.                 $joinType AST\Join::JOIN_TYPE_LEFT;
  1390.                 // Possible LEFT OUTER join
  1391.                 if ($this->lexer->isNextToken(Lexer::T_OUTER)) {
  1392.                     $this->match(Lexer::T_OUTER);
  1393.                     $joinType AST\Join::JOIN_TYPE_LEFTOUTER;
  1394.                 }
  1395.                 break;
  1396.             case ($this->lexer->isNextToken(Lexer::T_INNER)):
  1397.                 $this->match(Lexer::T_INNER);
  1398.                 break;
  1399.             default:
  1400.                 // Do nothing
  1401.         }
  1402.         $this->match(Lexer::T_JOIN);
  1403.         $next            $this->lexer->glimpse();
  1404.         $joinDeclaration = ($next['type'] === Lexer::T_DOT) ? $this->JoinAssociationDeclaration() : $this->RangeVariableDeclaration();
  1405.         $adhocConditions $this->lexer->isNextToken(Lexer::T_WITH);
  1406.         $join            = new AST\Join($joinType$joinDeclaration);
  1407.         // Describe non-root join declaration
  1408.         if ($joinDeclaration instanceof AST\RangeVariableDeclaration) {
  1409.             $joinDeclaration->isRoot false;
  1410.         }
  1411.         // Check for ad-hoc Join conditions
  1412.         if ($adhocConditions) {
  1413.             $this->match(Lexer::T_WITH);
  1414.             $join->conditionalExpression $this->ConditionalExpression();
  1415.         }
  1416.         return $join;
  1417.     }
  1418.     /**
  1419.      * RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
  1420.      *
  1421.      * @return \Doctrine\ORM\Query\AST\RangeVariableDeclaration
  1422.      *
  1423.      * @throws QueryException
  1424.      */
  1425.     public function RangeVariableDeclaration()
  1426.     {
  1427.         if ($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS) && $this->lexer->glimpse()['type'] === Lexer::T_SELECT) {
  1428.             $this->semanticalError('Subquery is not supported here'$this->lexer->token);
  1429.         }
  1430.         $abstractSchemaName $this->AbstractSchemaName();
  1431.         $this->validateAbstractSchemaName($abstractSchemaName);
  1432.         if ($this->lexer->isNextToken(Lexer::T_AS)) {
  1433.             $this->match(Lexer::T_AS);
  1434.         }
  1435.         $token $this->lexer->lookahead;
  1436.         $aliasIdentificationVariable $this->AliasIdentificationVariable();
  1437.         $classMetadata $this->em->getClassMetadata($abstractSchemaName);
  1438.         // Building queryComponent
  1439.         $queryComponent = [
  1440.             'metadata'     => $classMetadata,
  1441.             'parent'       => null,
  1442.             'relation'     => null,
  1443.             'map'          => null,
  1444.             'nestingLevel' => $this->nestingLevel,
  1445.             'token'        => $token
  1446.         ];
  1447.         $this->queryComponents[$aliasIdentificationVariable] = $queryComponent;
  1448.         return new AST\RangeVariableDeclaration($abstractSchemaName$aliasIdentificationVariable);
  1449.     }
  1450.     /**
  1451.      * JoinAssociationDeclaration ::= JoinAssociationPathExpression ["AS"] AliasIdentificationVariable [IndexBy]
  1452.      *
  1453.      * @return \Doctrine\ORM\Query\AST\JoinAssociationPathExpression
  1454.      */
  1455.     public function JoinAssociationDeclaration()
  1456.     {
  1457.         $joinAssociationPathExpression $this->JoinAssociationPathExpression();
  1458.         if ($this->lexer->isNextToken(Lexer::T_AS)) {
  1459.             $this->match(Lexer::T_AS);
  1460.         }
  1461.         $aliasIdentificationVariable $this->AliasIdentificationVariable();
  1462.         $indexBy                     $this->lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
  1463.         $identificationVariable $joinAssociationPathExpression->identificationVariable;
  1464.         $field                  $joinAssociationPathExpression->associationField;
  1465.         $class       $this->queryComponents[$identificationVariable]['metadata'];
  1466.         $targetClass $this->em->getClassMetadata($class->associationMappings[$field]['targetEntity']);
  1467.         // Building queryComponent
  1468.         $joinQueryComponent = [
  1469.             'metadata'     => $targetClass,
  1470.             'parent'       => $joinAssociationPathExpression->identificationVariable,
  1471.             'relation'     => $class->getAssociationMapping($field),
  1472.             'map'          => null,
  1473.             'nestingLevel' => $this->nestingLevel,
  1474.             'token'        => $this->lexer->lookahead
  1475.         ];
  1476.         $this->queryComponents[$aliasIdentificationVariable] = $joinQueryComponent;
  1477.         return new AST\JoinAssociationDeclaration($joinAssociationPathExpression$aliasIdentificationVariable$indexBy);
  1478.     }
  1479.     /**
  1480.      * PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet
  1481.      * PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}"
  1482.      *
  1483.      * @return \Doctrine\ORM\Query\AST\PartialObjectExpression
  1484.      */
  1485.     public function PartialObjectExpression()
  1486.     {
  1487.         $this->match(Lexer::T_PARTIAL);
  1488.         $partialFieldSet = [];
  1489.         $identificationVariable $this->IdentificationVariable();
  1490.         $this->match(Lexer::T_DOT);
  1491.         $this->match(Lexer::T_OPEN_CURLY_BRACE);
  1492.         $this->match(Lexer::T_IDENTIFIER);
  1493.         $field $this->lexer->token['value'];
  1494.         // First field in partial expression might be embeddable property
  1495.         while ($this->lexer->isNextToken(Lexer::T_DOT)) {
  1496.             $this->match(Lexer::T_DOT);
  1497.             $this->match(Lexer::T_IDENTIFIER);
  1498.             $field .= '.'.$this->lexer->token['value'];
  1499.         }
  1500.         $partialFieldSet[] = $field;
  1501.         while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
  1502.             $this->match(Lexer::T_COMMA);
  1503.             $this->match(Lexer::T_IDENTIFIER);
  1504.             $field $this->lexer->token['value'];
  1505.             while ($this->lexer->isNextToken(Lexer::T_DOT)) {
  1506.                 $this->match(Lexer::T_DOT);
  1507.                 $this->match(Lexer::T_IDENTIFIER);
  1508.                 $field .= '.'.$this->lexer->token['value'];
  1509.             }
  1510.             $partialFieldSet[] = $field;
  1511.         }
  1512.         $this->match(Lexer::T_CLOSE_CURLY_BRACE);
  1513.         $partialObjectExpression = new AST\PartialObjectExpression($identificationVariable$partialFieldSet);
  1514.         // Defer PartialObjectExpression validation
  1515.         $this->deferredPartialObjectExpressions[] = [
  1516.             'expression'   => $partialObjectExpression,
  1517.             'nestingLevel' => $this->nestingLevel,
  1518.             'token'        => $this->lexer->token,
  1519.         ];
  1520.         return $partialObjectExpression;
  1521.     }
  1522.     /**
  1523.      * NewObjectExpression ::= "NEW" AbstractSchemaName "(" NewObjectArg {"," NewObjectArg}* ")"
  1524.      *
  1525.      * @return \Doctrine\ORM\Query\AST\NewObjectExpression
  1526.      */
  1527.     public function NewObjectExpression()
  1528.     {
  1529.         $this->match(Lexer::T_NEW);
  1530.         $className $this->AbstractSchemaName(); // note that this is not yet validated
  1531.         $token $this->lexer->token;
  1532.         $this->match(Lexer::T_OPEN_PARENTHESIS);
  1533.         $args[] = $this->NewObjectArg();
  1534.         while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
  1535.             $this->match(Lexer::T_COMMA);
  1536.             $args[] = $this->NewObjectArg();
  1537.         }
  1538.         $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1539.         $expression = new AST\NewObjectExpression($className$args);
  1540.         // Defer NewObjectExpression validation
  1541.         $this->deferredNewObjectExpressions[] = [
  1542.             'token'        => $token,
  1543.             'expression'   => $expression,
  1544.             'nestingLevel' => $this->nestingLevel,
  1545.         ];
  1546.         return $expression;
  1547.     }
  1548.     /**
  1549.      * NewObjectArg ::= ScalarExpression | "(" Subselect ")"
  1550.      *
  1551.      * @return mixed
  1552.      */
  1553.     public function NewObjectArg()
  1554.     {
  1555.         $token $this->lexer->lookahead;
  1556.         $peek  $this->lexer->glimpse();
  1557.         if ($token['type'] === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT) {
  1558.             $this->match(Lexer::T_OPEN_PARENTHESIS);
  1559.             $expression $this->Subselect();
  1560.             $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1561.             return $expression;
  1562.         }
  1563.         return $this->ScalarExpression();
  1564.     }
  1565.     /**
  1566.      * IndexBy ::= "INDEX" "BY" StateFieldPathExpression
  1567.      *
  1568.      * @return \Doctrine\ORM\Query\AST\IndexBy
  1569.      */
  1570.     public function IndexBy()
  1571.     {
  1572.         $this->match(Lexer::T_INDEX);
  1573.         $this->match(Lexer::T_BY);
  1574.         $pathExpr $this->StateFieldPathExpression();
  1575.         // Add the INDEX BY info to the query component
  1576.         $this->queryComponents[$pathExpr->identificationVariable]['map'] = $pathExpr->field;
  1577.         return new AST\IndexBy($pathExpr);
  1578.     }
  1579.     /**
  1580.      * ScalarExpression ::= SimpleArithmeticExpression | StringPrimary | DateTimePrimary |
  1581.      *                      StateFieldPathExpression | BooleanPrimary | CaseExpression |
  1582.      *                      InstanceOfExpression
  1583.      *
  1584.      * @return mixed One of the possible expressions or subexpressions.
  1585.      */
  1586.     public function ScalarExpression()
  1587.     {
  1588.         $lookahead $this->lexer->lookahead['type'];
  1589.         $peek      $this->lexer->glimpse();
  1590.         switch (true) {
  1591.             case ($lookahead === Lexer::T_INTEGER):
  1592.             case ($lookahead === Lexer::T_FLOAT):
  1593.             // SimpleArithmeticExpression : (- u.value ) or ( + u.value )  or ( - 1 ) or ( + 1 )
  1594.             case ($lookahead === Lexer::T_MINUS):
  1595.             case ($lookahead === Lexer::T_PLUS):
  1596.                 return $this->SimpleArithmeticExpression();
  1597.             case ($lookahead === Lexer::T_STRING):
  1598.                 return $this->StringPrimary();
  1599.             case ($lookahead === Lexer::T_TRUE):
  1600.             case ($lookahead === Lexer::T_FALSE):
  1601.                 $this->match($lookahead);
  1602.                 return new AST\Literal(AST\Literal::BOOLEAN$this->lexer->token['value']);
  1603.             case ($lookahead === Lexer::T_INPUT_PARAMETER):
  1604.                 switch (true) {
  1605.                     case $this->isMathOperator($peek):
  1606.                         // :param + u.value
  1607.                         return $this->SimpleArithmeticExpression();
  1608.                     default:
  1609.                         return $this->InputParameter();
  1610.                 }
  1611.             case ($lookahead === Lexer::T_CASE):
  1612.             case ($lookahead === Lexer::T_COALESCE):
  1613.             case ($lookahead === Lexer::T_NULLIF):
  1614.                 // Since NULLIF and COALESCE can be identified as a function,
  1615.                 // we need to check these before checking for FunctionDeclaration
  1616.                 return $this->CaseExpression();
  1617.             case ($lookahead === Lexer::T_OPEN_PARENTHESIS):
  1618.                 return $this->SimpleArithmeticExpression();
  1619.             // this check must be done before checking for a filed path expression
  1620.             case ($this->isFunction()):
  1621.                 $this->lexer->peek(); // "("
  1622.                 switch (true) {
  1623.                     case ($this->isMathOperator($this->peekBeyondClosingParenthesis())):
  1624.                         // SUM(u.id) + COUNT(u.id)
  1625.                         return $this->SimpleArithmeticExpression();
  1626.                     default:
  1627.                         // IDENTITY(u)
  1628.                         return $this->FunctionDeclaration();
  1629.                 }
  1630.                 break;
  1631.             // it is no function, so it must be a field path
  1632.             case ($lookahead === Lexer::T_IDENTIFIER):
  1633.                 $this->lexer->peek(); // lookahead => '.'
  1634.                 $this->lexer->peek(); // lookahead => token after '.'
  1635.                 $peek $this->lexer->peek(); // lookahead => token after the token after the '.'
  1636.                 $this->lexer->resetPeek();
  1637.                 if ($this->isMathOperator($peek)) {
  1638.                     return $this->SimpleArithmeticExpression();
  1639.                 }
  1640.                 return $this->StateFieldPathExpression();
  1641.             default:
  1642.                 $this->syntaxError();
  1643.         }
  1644.     }
  1645.     /**
  1646.      * CaseExpression ::= GeneralCaseExpression | SimpleCaseExpression | CoalesceExpression | NullifExpression
  1647.      * GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END"
  1648.      * WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpression
  1649.      * SimpleCaseExpression ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}* "ELSE" ScalarExpression "END"
  1650.      * CaseOperand ::= StateFieldPathExpression | TypeDiscriminator
  1651.      * SimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpression
  1652.      * CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")"
  1653.      * NullifExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")"
  1654.      *
  1655.      * @return mixed One of the possible expressions or subexpressions.
  1656.      */
  1657.     public function CaseExpression()
  1658.     {
  1659.         $lookahead $this->lexer->lookahead['type'];
  1660.         switch ($lookahead) {
  1661.             case Lexer::T_NULLIF:
  1662.                 return $this->NullIfExpression();
  1663.             case Lexer::T_COALESCE:
  1664.                 return $this->CoalesceExpression();
  1665.             case Lexer::T_CASE:
  1666.                 $this->lexer->resetPeek();
  1667.                 $peek $this->lexer->peek();
  1668.                 if ($peek['type'] === Lexer::T_WHEN) {
  1669.                     return $this->GeneralCaseExpression();
  1670.                 }
  1671.                 return $this->SimpleCaseExpression();
  1672.             default:
  1673.                 // Do nothing
  1674.                 break;
  1675.         }
  1676.         $this->syntaxError();
  1677.     }
  1678.     /**
  1679.      * CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")"
  1680.      *
  1681.      * @return \Doctrine\ORM\Query\AST\CoalesceExpression
  1682.      */
  1683.     public function CoalesceExpression()
  1684.     {
  1685.         $this->match(Lexer::T_COALESCE);
  1686.         $this->match(Lexer::T_OPEN_PARENTHESIS);
  1687.         // Process ScalarExpressions (1..N)
  1688.         $scalarExpressions = [];
  1689.         $scalarExpressions[] = $this->ScalarExpression();
  1690.         while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
  1691.             $this->match(Lexer::T_COMMA);
  1692.             $scalarExpressions[] = $this->ScalarExpression();
  1693.         }
  1694.         $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1695.         return new AST\CoalesceExpression($scalarExpressions);
  1696.     }
  1697.     /**
  1698.      * NullIfExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")"
  1699.      *
  1700.      * @return \Doctrine\ORM\Query\AST\NullIfExpression
  1701.      */
  1702.     public function NullIfExpression()
  1703.     {
  1704.         $this->match(Lexer::T_NULLIF);
  1705.         $this->match(Lexer::T_OPEN_PARENTHESIS);
  1706.         $firstExpression $this->ScalarExpression();
  1707.         $this->match(Lexer::T_COMMA);
  1708.         $secondExpression $this->ScalarExpression();
  1709.         $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1710.         return new AST\NullIfExpression($firstExpression$secondExpression);
  1711.     }
  1712.     /**
  1713.      * GeneralCaseExpression ::= "CASE" WhenClause {WhenClause}* "ELSE" ScalarExpression "END"
  1714.      *
  1715.      * @return \Doctrine\ORM\Query\AST\GeneralCaseExpression
  1716.      */
  1717.     public function GeneralCaseExpression()
  1718.     {
  1719.         $this->match(Lexer::T_CASE);
  1720.         // Process WhenClause (1..N)
  1721.         $whenClauses = [];
  1722.         do {
  1723.             $whenClauses[] = $this->WhenClause();
  1724.         } while ($this->lexer->isNextToken(Lexer::T_WHEN));
  1725.         $this->match(Lexer::T_ELSE);
  1726.         $scalarExpression $this->ScalarExpression();
  1727.         $this->match(Lexer::T_END);
  1728.         return new AST\GeneralCaseExpression($whenClauses$scalarExpression);
  1729.     }
  1730.     /**
  1731.      * SimpleCaseExpression ::= "CASE" CaseOperand SimpleWhenClause {SimpleWhenClause}* "ELSE" ScalarExpression "END"
  1732.      * CaseOperand ::= StateFieldPathExpression | TypeDiscriminator
  1733.      *
  1734.      * @return AST\SimpleCaseExpression
  1735.      */
  1736.     public function SimpleCaseExpression()
  1737.     {
  1738.         $this->match(Lexer::T_CASE);
  1739.         $caseOperand $this->StateFieldPathExpression();
  1740.         // Process SimpleWhenClause (1..N)
  1741.         $simpleWhenClauses = [];
  1742.         do {
  1743.             $simpleWhenClauses[] = $this->SimpleWhenClause();
  1744.         } while ($this->lexer->isNextToken(Lexer::T_WHEN));
  1745.         $this->match(Lexer::T_ELSE);
  1746.         $scalarExpression $this->ScalarExpression();
  1747.         $this->match(Lexer::T_END);
  1748.         return new AST\SimpleCaseExpression($caseOperand$simpleWhenClauses$scalarExpression);
  1749.     }
  1750.     /**
  1751.      * WhenClause ::= "WHEN" ConditionalExpression "THEN" ScalarExpression
  1752.      *
  1753.      * @return \Doctrine\ORM\Query\AST\WhenClause
  1754.      */
  1755.     public function WhenClause()
  1756.     {
  1757.         $this->match(Lexer::T_WHEN);
  1758.         $conditionalExpression $this->ConditionalExpression();
  1759.         $this->match(Lexer::T_THEN);
  1760.         return new AST\WhenClause($conditionalExpression$this->ScalarExpression());
  1761.     }
  1762.     /**
  1763.      * SimpleWhenClause ::= "WHEN" ScalarExpression "THEN" ScalarExpression
  1764.      *
  1765.      * @return \Doctrine\ORM\Query\AST\SimpleWhenClause
  1766.      */
  1767.     public function SimpleWhenClause()
  1768.     {
  1769.         $this->match(Lexer::T_WHEN);
  1770.         $conditionalExpression $this->ScalarExpression();
  1771.         $this->match(Lexer::T_THEN);
  1772.         return new AST\SimpleWhenClause($conditionalExpression$this->ScalarExpression());
  1773.     }
  1774.     /**
  1775.      * SelectExpression ::= (
  1776.      *     IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration |
  1777.      *     PartialObjectExpression | "(" Subselect ")" | CaseExpression | NewObjectExpression
  1778.      * ) [["AS"] ["HIDDEN"] AliasResultVariable]
  1779.      *
  1780.      * @return \Doctrine\ORM\Query\AST\SelectExpression
  1781.      */
  1782.     public function SelectExpression()
  1783.     {
  1784.         $expression    null;
  1785.         $identVariable null;
  1786.         $peek          $this->lexer->glimpse();
  1787.         $lookaheadType $this->lexer->lookahead['type'];
  1788.         switch (true) {
  1789.             // ScalarExpression (u.name)
  1790.             case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] === Lexer::T_DOT):
  1791.                 $expression $this->ScalarExpression();
  1792.                 break;
  1793.             // IdentificationVariable (u)
  1794.             case ($lookaheadType === Lexer::T_IDENTIFIER && $peek['type'] !== Lexer::T_OPEN_PARENTHESIS):
  1795.                 $expression $identVariable $this->IdentificationVariable();
  1796.                 break;
  1797.             // CaseExpression (CASE ... or NULLIF(...) or COALESCE(...))
  1798.             case ($lookaheadType === Lexer::T_CASE):
  1799.             case ($lookaheadType === Lexer::T_COALESCE):
  1800.             case ($lookaheadType === Lexer::T_NULLIF):
  1801.                 $expression $this->CaseExpression();
  1802.                 break;
  1803.             // DQL Function (SUM(u.value) or SUM(u.value) + 1)
  1804.             case ($this->isFunction()):
  1805.                 $this->lexer->peek(); // "("
  1806.                 switch (true) {
  1807.                     case ($this->isMathOperator($this->peekBeyondClosingParenthesis())):
  1808.                         // SUM(u.id) + COUNT(u.id)
  1809.                         $expression $this->ScalarExpression();
  1810.                         break;
  1811.                     default:
  1812.                         // IDENTITY(u)
  1813.                         $expression $this->FunctionDeclaration();
  1814.                         break;
  1815.                 }
  1816.                 break;
  1817.             // PartialObjectExpression (PARTIAL u.{id, name})
  1818.             case ($lookaheadType === Lexer::T_PARTIAL):
  1819.                 $expression    $this->PartialObjectExpression();
  1820.                 $identVariable $expression->identificationVariable;
  1821.                 break;
  1822.             // Subselect
  1823.             case ($lookaheadType === Lexer::T_OPEN_PARENTHESIS && $peek['type'] === Lexer::T_SELECT):
  1824.                 $this->match(Lexer::T_OPEN_PARENTHESIS);
  1825.                 $expression $this->Subselect();
  1826.                 $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1827.                 break;
  1828.             // Shortcut: ScalarExpression => SimpleArithmeticExpression
  1829.             case ($lookaheadType === Lexer::T_OPEN_PARENTHESIS):
  1830.             case ($lookaheadType === Lexer::T_INTEGER):
  1831.             case ($lookaheadType === Lexer::T_STRING):
  1832.             case ($lookaheadType === Lexer::T_FLOAT):
  1833.             // SimpleArithmeticExpression : (- u.value ) or ( + u.value )
  1834.             case ($lookaheadType === Lexer::T_MINUS):
  1835.             case ($lookaheadType === Lexer::T_PLUS):
  1836.                 $expression $this->SimpleArithmeticExpression();
  1837.                 break;
  1838.             // NewObjectExpression (New ClassName(id, name))
  1839.             case ($lookaheadType === Lexer::T_NEW):
  1840.                 $expression $this->NewObjectExpression();
  1841.                 break;
  1842.             default:
  1843.                 $this->syntaxError(
  1844.                     'IdentificationVariable | ScalarExpression | AggregateExpression | FunctionDeclaration | PartialObjectExpression | "(" Subselect ")" | CaseExpression',
  1845.                     $this->lexer->lookahead
  1846.                 );
  1847.         }
  1848.         // [["AS"] ["HIDDEN"] AliasResultVariable]
  1849.         $mustHaveAliasResultVariable false;
  1850.         if ($this->lexer->isNextToken(Lexer::T_AS)) {
  1851.             $this->match(Lexer::T_AS);
  1852.             $mustHaveAliasResultVariable true;
  1853.         }
  1854.         $hiddenAliasResultVariable false;
  1855.         if ($this->lexer->isNextToken(Lexer::T_HIDDEN)) {
  1856.             $this->match(Lexer::T_HIDDEN);
  1857.             $hiddenAliasResultVariable true;
  1858.         }
  1859.         $aliasResultVariable null;
  1860.         if ($mustHaveAliasResultVariable || $this->lexer->isNextToken(Lexer::T_IDENTIFIER)) {
  1861.             $token $this->lexer->lookahead;
  1862.             $aliasResultVariable $this->AliasResultVariable();
  1863.             // Include AliasResultVariable in query components.
  1864.             $this->queryComponents[$aliasResultVariable] = [
  1865.                 'resultVariable' => $expression,
  1866.                 'nestingLevel'   => $this->nestingLevel,
  1867.                 'token'          => $token,
  1868.             ];
  1869.         }
  1870.         // AST
  1871.         $expr = new AST\SelectExpression($expression$aliasResultVariable$hiddenAliasResultVariable);
  1872.         if ($identVariable) {
  1873.             $this->identVariableExpressions[$identVariable] = $expr;
  1874.         }
  1875.         return $expr;
  1876.     }
  1877.     /**
  1878.      * SimpleSelectExpression ::= (
  1879.      *      StateFieldPathExpression | IdentificationVariable | FunctionDeclaration |
  1880.      *      AggregateExpression | "(" Subselect ")" | ScalarExpression
  1881.      * ) [["AS"] AliasResultVariable]
  1882.      *
  1883.      * @return \Doctrine\ORM\Query\AST\SimpleSelectExpression
  1884.      */
  1885.     public function SimpleSelectExpression()
  1886.     {
  1887.         $peek $this->lexer->glimpse();
  1888.         switch ($this->lexer->lookahead['type']) {
  1889.             case Lexer::T_IDENTIFIER:
  1890.                 switch (true) {
  1891.                     case ($peek['type'] === Lexer::T_DOT):
  1892.                         $expression $this->StateFieldPathExpression();
  1893.                         return new AST\SimpleSelectExpression($expression);
  1894.                     case ($peek['type'] !== Lexer::T_OPEN_PARENTHESIS):
  1895.                         $expression $this->IdentificationVariable();
  1896.                         return new AST\SimpleSelectExpression($expression);
  1897.                     case ($this->isFunction()):
  1898.                         // SUM(u.id) + COUNT(u.id)
  1899.                         if ($this->isMathOperator($this->peekBeyondClosingParenthesis())) {
  1900.                             return new AST\SimpleSelectExpression($this->ScalarExpression());
  1901.                         }
  1902.                         // COUNT(u.id)
  1903.                         if ($this->isAggregateFunction($this->lexer->lookahead['type'])) {
  1904.                             return new AST\SimpleSelectExpression($this->AggregateExpression());
  1905.                         }
  1906.                         // IDENTITY(u)
  1907.                         return new AST\SimpleSelectExpression($this->FunctionDeclaration());
  1908.                     default:
  1909.                         // Do nothing
  1910.                 }
  1911.                 break;
  1912.             case Lexer::T_OPEN_PARENTHESIS:
  1913.                 if ($peek['type'] !== Lexer::T_SELECT) {
  1914.                     // Shortcut: ScalarExpression => SimpleArithmeticExpression
  1915.                     $expression $this->SimpleArithmeticExpression();
  1916.                     return new AST\SimpleSelectExpression($expression);
  1917.                 }
  1918.                 // Subselect
  1919.                 $this->match(Lexer::T_OPEN_PARENTHESIS);
  1920.                 $expression $this->Subselect();
  1921.                 $this->match(Lexer::T_CLOSE_PARENTHESIS);
  1922.                 return new AST\SimpleSelectExpression($expression);
  1923.             default:
  1924.                 // Do nothing
  1925.         }
  1926.         $this->lexer->peek();
  1927.         $expression $this->ScalarExpression();
  1928.         $expr       = new AST\SimpleSelectExpression($expression);
  1929.         if ($this->lexer->isNextToken(Lexer::T_AS)) {
  1930.             $this->match(Lexer::T_AS);
  1931.         }
  1932.         if ($this->lexer->isNextToken(Lexer::T_IDENTIFIER)) {
  1933.             $token $this->lexer->lookahead;
  1934.             $resultVariable $this->AliasResultVariable();
  1935.             $expr->fieldIdentificationVariable $resultVariable;
  1936.             // Include AliasResultVariable in query components.
  1937.             $this->queryComponents[$resultVariable] = [
  1938.                 'resultvariable' => $expr,
  1939.                 'nestingLevel'   => $this->nestingLevel,
  1940.                 'token'          => $token,
  1941.             ];
  1942.         }
  1943.         return $expr;
  1944.     }
  1945.     /**
  1946.      * ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}*
  1947.      *
  1948.      * @return \Doctrine\ORM\Query\AST\ConditionalExpression
  1949.      */
  1950.     public function ConditionalExpression()
  1951.     {
  1952.         $conditionalTerms = [];
  1953.         $conditionalTerms[] = $this->ConditionalTerm();
  1954.         while ($this->lexer->isNextToken(Lexer::T_OR)) {
  1955.             $this->match(Lexer::T_OR);
  1956.             $conditionalTerms[] = $this->ConditionalTerm();
  1957.         }
  1958.         // Phase 1 AST optimization: Prevent AST\ConditionalExpression
  1959.         // if only one AST\ConditionalTerm is defined
  1960.         if (count($conditionalTerms) == 1) {
  1961.             return $conditionalTerms[0];
  1962.         }
  1963.         return new AST\ConditionalExpression($conditionalTerms);
  1964.     }
  1965.     /**
  1966.      * ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}*
  1967.      *
  1968.      * @return \Doctrine\ORM\Query\AST\ConditionalTerm
  1969.      */
  1970.     public function ConditionalTerm()
  1971.     {
  1972.         $conditionalFactors = [];
  1973.         $conditionalFactors[] = $this->ConditionalFactor();
  1974.         while ($this->lexer->isNextToken(Lexer::T_AND)) {
  1975.             $this->match(Lexer::T_AND);
  1976.             $conditionalFactors[] = $this->ConditionalFactor();
  1977.         }
  1978.         // Phase 1 AST optimization: Prevent AST\ConditionalTerm
  1979.         // if only one AST\ConditionalFactor is defined
  1980.         if (count($conditionalFactors) == 1) {
  1981.             return $conditionalFactors[0];
  1982.         }
  1983.         return new AST\ConditionalTerm($conditionalFactors);
  1984.     }
  1985.     /**
  1986.      * ConditionalFactor ::= ["NOT"] ConditionalPrimary
  1987.      *
  1988.      * @return \Doctrine\ORM\Query\AST\ConditionalFactor
  1989.      */
  1990.     public function ConditionalFactor()
  1991.     {
  1992.         $not false;
  1993.         if ($this->lexer->isNextToken(Lexer::T_NOT)) {
  1994.             $this->match(Lexer::T_NOT);
  1995.             $not true;
  1996.         }
  1997.         $conditionalPrimary $this->ConditionalPrimary();
  1998.         // Phase 1 AST optimization: Prevent AST\ConditionalFactor
  1999.         // if only one AST\ConditionalPrimary is defined
  2000.         if ( ! $not) {
  2001.             return $conditionalPrimary;
  2002.         }
  2003.         $conditionalFactor = new AST\ConditionalFactor($conditionalPrimary);
  2004.         $conditionalFactor->not $not;
  2005.         return $conditionalFactor;
  2006.     }
  2007.     /**
  2008.      * ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")"
  2009.      *
  2010.      * @return \Doctrine\ORM\Query\AST\ConditionalPrimary
  2011.      */
  2012.     public function ConditionalPrimary()
  2013.     {
  2014.         $condPrimary = new AST\ConditionalPrimary;
  2015.         if ( ! $this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
  2016.             $condPrimary->simpleConditionalExpression $this->SimpleConditionalExpression();
  2017.             return $condPrimary;
  2018.         }
  2019.         // Peek beyond the matching closing parenthesis ')'
  2020.         $peek $this->peekBeyondClosingParenthesis();
  2021.         if ($peek !== null && (
  2022.             in_array($peek['value'], ['=''<''<=''<>''>''>=''!=']) ||
  2023.             in_array($peek['type'], [Lexer::T_NOTLexer::T_BETWEENLexer::T_LIKELexer::T_INLexer::T_ISLexer::T_EXISTS]) ||
  2024.             $this->isMathOperator($peek)
  2025.         )) {
  2026.             $condPrimary->simpleConditionalExpression $this->SimpleConditionalExpression();
  2027.             return $condPrimary;
  2028.         }
  2029.         $this->match(Lexer::T_OPEN_PARENTHESIS);
  2030.         $condPrimary->conditionalExpression $this->ConditionalExpression();
  2031.         $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2032.         return $condPrimary;
  2033.     }
  2034.     /**
  2035.      * SimpleConditionalExpression ::=
  2036.      *      ComparisonExpression | BetweenExpression | LikeExpression |
  2037.      *      InExpression | NullComparisonExpression | ExistsExpression |
  2038.      *      EmptyCollectionComparisonExpression | CollectionMemberExpression |
  2039.      *      InstanceOfExpression
  2040.      */
  2041.     public function SimpleConditionalExpression()
  2042.     {
  2043.         if ($this->lexer->isNextToken(Lexer::T_EXISTS)) {
  2044.             return $this->ExistsExpression();
  2045.         }
  2046.         $token      $this->lexer->lookahead;
  2047.         $peek       $this->lexer->glimpse();
  2048.         $lookahead  $token;
  2049.         if ($this->lexer->isNextToken(Lexer::T_NOT)) {
  2050.             $token $this->lexer->glimpse();
  2051.         }
  2052.         if ($token['type'] === Lexer::T_IDENTIFIER || $token['type'] === Lexer::T_INPUT_PARAMETER || $this->isFunction()) {
  2053.             // Peek beyond the matching closing parenthesis.
  2054.             $beyond $this->lexer->peek();
  2055.             switch ($peek['value']) {
  2056.                 case '(':
  2057.                     // Peeks beyond the matched closing parenthesis.
  2058.                     $token $this->peekBeyondClosingParenthesis(false);
  2059.                     if ($token['type'] === Lexer::T_NOT) {
  2060.                         $token $this->lexer->peek();
  2061.                     }
  2062.                     if ($token['type'] === Lexer::T_IS) {
  2063.                         $lookahead $this->lexer->peek();
  2064.                     }
  2065.                     break;
  2066.                 default:
  2067.                     // Peek beyond the PathExpression or InputParameter.
  2068.                     $token $beyond;
  2069.                     while ($token['value'] === '.') {
  2070.                         $this->lexer->peek();
  2071.                         $token $this->lexer->peek();
  2072.                     }
  2073.                     // Also peek beyond a NOT if there is one.
  2074.                     if ($token['type'] === Lexer::T_NOT) {
  2075.                         $token $this->lexer->peek();
  2076.                     }
  2077.                     // We need to go even further in case of IS (differentiate between NULL and EMPTY)
  2078.                     $lookahead $this->lexer->peek();
  2079.             }
  2080.             // Also peek beyond a NOT if there is one.
  2081.             if ($lookahead['type'] === Lexer::T_NOT) {
  2082.                 $lookahead $this->lexer->peek();
  2083.             }
  2084.             $this->lexer->resetPeek();
  2085.         }
  2086.         if ($token['type'] === Lexer::T_BETWEEN) {
  2087.             return $this->BetweenExpression();
  2088.         }
  2089.         if ($token['type'] === Lexer::T_LIKE) {
  2090.             return $this->LikeExpression();
  2091.         }
  2092.         if ($token['type'] === Lexer::T_IN) {
  2093.             return $this->InExpression();
  2094.         }
  2095.         if ($token['type'] === Lexer::T_INSTANCE) {
  2096.             return $this->InstanceOfExpression();
  2097.         }
  2098.         if ($token['type'] === Lexer::T_MEMBER) {
  2099.             return $this->CollectionMemberExpression();
  2100.         }
  2101.         if ($token['type'] === Lexer::T_IS && $lookahead['type'] === Lexer::T_NULL) {
  2102.             return $this->NullComparisonExpression();
  2103.         }
  2104.         if ($token['type'] === Lexer::T_IS  && $lookahead['type'] === Lexer::T_EMPTY) {
  2105.             return $this->EmptyCollectionComparisonExpression();
  2106.         }
  2107.         return $this->ComparisonExpression();
  2108.     }
  2109.     /**
  2110.      * EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"
  2111.      *
  2112.      * @return \Doctrine\ORM\Query\AST\EmptyCollectionComparisonExpression
  2113.      */
  2114.     public function EmptyCollectionComparisonExpression()
  2115.     {
  2116.         $emptyCollectionCompExpr = new AST\EmptyCollectionComparisonExpression(
  2117.             $this->CollectionValuedPathExpression()
  2118.         );
  2119.         $this->match(Lexer::T_IS);
  2120.         if ($this->lexer->isNextToken(Lexer::T_NOT)) {
  2121.             $this->match(Lexer::T_NOT);
  2122.             $emptyCollectionCompExpr->not true;
  2123.         }
  2124.         $this->match(Lexer::T_EMPTY);
  2125.         return $emptyCollectionCompExpr;
  2126.     }
  2127.     /**
  2128.      * CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression
  2129.      *
  2130.      * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression
  2131.      * SimpleEntityExpression ::= IdentificationVariable | InputParameter
  2132.      *
  2133.      * @return \Doctrine\ORM\Query\AST\CollectionMemberExpression
  2134.      */
  2135.     public function CollectionMemberExpression()
  2136.     {
  2137.         $not        false;
  2138.         $entityExpr $this->EntityExpression();
  2139.         if ($this->lexer->isNextToken(Lexer::T_NOT)) {
  2140.             $this->match(Lexer::T_NOT);
  2141.             $not true;
  2142.         }
  2143.         $this->match(Lexer::T_MEMBER);
  2144.         if ($this->lexer->isNextToken(Lexer::T_OF)) {
  2145.             $this->match(Lexer::T_OF);
  2146.         }
  2147.         $collMemberExpr = new AST\CollectionMemberExpression(
  2148.             $entityExpr$this->CollectionValuedPathExpression()
  2149.         );
  2150.         $collMemberExpr->not $not;
  2151.         return $collMemberExpr;
  2152.     }
  2153.     /**
  2154.      * Literal ::= string | char | integer | float | boolean
  2155.      *
  2156.      * @return \Doctrine\ORM\Query\AST\Literal
  2157.      */
  2158.     public function Literal()
  2159.     {
  2160.         switch ($this->lexer->lookahead['type']) {
  2161.             case Lexer::T_STRING:
  2162.                 $this->match(Lexer::T_STRING);
  2163.                 return new AST\Literal(AST\Literal::STRING$this->lexer->token['value']);
  2164.             case Lexer::T_INTEGER:
  2165.             case Lexer::T_FLOAT:
  2166.                 $this->match(
  2167.                     $this->lexer->isNextToken(Lexer::T_INTEGER) ? Lexer::T_INTEGER Lexer::T_FLOAT
  2168.                 );
  2169.                 return new AST\Literal(AST\Literal::NUMERIC$this->lexer->token['value']);
  2170.             case Lexer::T_TRUE:
  2171.             case Lexer::T_FALSE:
  2172.                 $this->match(
  2173.                     $this->lexer->isNextToken(Lexer::T_TRUE) ? Lexer::T_TRUE Lexer::T_FALSE
  2174.                 );
  2175.                 return new AST\Literal(AST\Literal::BOOLEAN$this->lexer->token['value']);
  2176.             default:
  2177.                 $this->syntaxError('Literal');
  2178.         }
  2179.     }
  2180.     /**
  2181.      * InParameter ::= Literal | InputParameter
  2182.      *
  2183.      * @return string | \Doctrine\ORM\Query\AST\InputParameter
  2184.      */
  2185.     public function InParameter()
  2186.     {
  2187.         if ($this->lexer->lookahead['type'] == Lexer::T_INPUT_PARAMETER) {
  2188.             return $this->InputParameter();
  2189.         }
  2190.         return $this->Literal();
  2191.     }
  2192.     /**
  2193.      * InputParameter ::= PositionalParameter | NamedParameter
  2194.      *
  2195.      * @return \Doctrine\ORM\Query\AST\InputParameter
  2196.      */
  2197.     public function InputParameter()
  2198.     {
  2199.         $this->match(Lexer::T_INPUT_PARAMETER);
  2200.         return new AST\InputParameter($this->lexer->token['value']);
  2201.     }
  2202.     /**
  2203.      * ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")"
  2204.      *
  2205.      * @return \Doctrine\ORM\Query\AST\ArithmeticExpression
  2206.      */
  2207.     public function ArithmeticExpression()
  2208.     {
  2209.         $expr = new AST\ArithmeticExpression;
  2210.         if ($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
  2211.             $peek $this->lexer->glimpse();
  2212.             if ($peek['type'] === Lexer::T_SELECT) {
  2213.                 $this->match(Lexer::T_OPEN_PARENTHESIS);
  2214.                 $expr->subselect $this->Subselect();
  2215.                 $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2216.                 return $expr;
  2217.             }
  2218.         }
  2219.         $expr->simpleArithmeticExpression $this->SimpleArithmeticExpression();
  2220.         return $expr;
  2221.     }
  2222.     /**
  2223.      * SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}*
  2224.      *
  2225.      * @return \Doctrine\ORM\Query\AST\SimpleArithmeticExpression
  2226.      */
  2227.     public function SimpleArithmeticExpression()
  2228.     {
  2229.         $terms = [];
  2230.         $terms[] = $this->ArithmeticTerm();
  2231.         while (($isPlus $this->lexer->isNextToken(Lexer::T_PLUS)) || $this->lexer->isNextToken(Lexer::T_MINUS)) {
  2232.             $this->match(($isPlus) ? Lexer::T_PLUS Lexer::T_MINUS);
  2233.             $terms[] = $this->lexer->token['value'];
  2234.             $terms[] = $this->ArithmeticTerm();
  2235.         }
  2236.         // Phase 1 AST optimization: Prevent AST\SimpleArithmeticExpression
  2237.         // if only one AST\ArithmeticTerm is defined
  2238.         if (count($terms) == 1) {
  2239.             return $terms[0];
  2240.         }
  2241.         return new AST\SimpleArithmeticExpression($terms);
  2242.     }
  2243.     /**
  2244.      * ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}*
  2245.      *
  2246.      * @return \Doctrine\ORM\Query\AST\ArithmeticTerm
  2247.      */
  2248.     public function ArithmeticTerm()
  2249.     {
  2250.         $factors = [];
  2251.         $factors[] = $this->ArithmeticFactor();
  2252.         while (($isMult $this->lexer->isNextToken(Lexer::T_MULTIPLY)) || $this->lexer->isNextToken(Lexer::T_DIVIDE)) {
  2253.             $this->match(($isMult) ? Lexer::T_MULTIPLY Lexer::T_DIVIDE);
  2254.             $factors[] = $this->lexer->token['value'];
  2255.             $factors[] = $this->ArithmeticFactor();
  2256.         }
  2257.         // Phase 1 AST optimization: Prevent AST\ArithmeticTerm
  2258.         // if only one AST\ArithmeticFactor is defined
  2259.         if (count($factors) == 1) {
  2260.             return $factors[0];
  2261.         }
  2262.         return new AST\ArithmeticTerm($factors);
  2263.     }
  2264.     /**
  2265.      * ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary
  2266.      *
  2267.      * @return \Doctrine\ORM\Query\AST\ArithmeticFactor
  2268.      */
  2269.     public function ArithmeticFactor()
  2270.     {
  2271.         $sign null;
  2272.         if (($isPlus $this->lexer->isNextToken(Lexer::T_PLUS)) || $this->lexer->isNextToken(Lexer::T_MINUS)) {
  2273.             $this->match(($isPlus) ? Lexer::T_PLUS Lexer::T_MINUS);
  2274.             $sign $isPlus;
  2275.         }
  2276.         $primary $this->ArithmeticPrimary();
  2277.         // Phase 1 AST optimization: Prevent AST\ArithmeticFactor
  2278.         // if only one AST\ArithmeticPrimary is defined
  2279.         if ($sign === null) {
  2280.             return $primary;
  2281.         }
  2282.         return new AST\ArithmeticFactor($primary$sign);
  2283.     }
  2284.     /**
  2285.      * ArithmeticPrimary ::= SingleValuedPathExpression | Literal | ParenthesisExpression
  2286.      *          | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings
  2287.      *          | FunctionsReturningDatetime | IdentificationVariable | ResultVariable
  2288.      *          | InputParameter | CaseExpression
  2289.      */
  2290.     public function ArithmeticPrimary()
  2291.     {
  2292.         if ($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
  2293.             $this->match(Lexer::T_OPEN_PARENTHESIS);
  2294.             $expr $this->SimpleArithmeticExpression();
  2295.             $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2296.             return new AST\ParenthesisExpression($expr);
  2297.         }
  2298.         switch ($this->lexer->lookahead['type']) {
  2299.             case Lexer::T_COALESCE:
  2300.             case Lexer::T_NULLIF:
  2301.             case Lexer::T_CASE:
  2302.                 return $this->CaseExpression();
  2303.             case Lexer::T_IDENTIFIER:
  2304.                 $peek $this->lexer->glimpse();
  2305.                 if ($peek !== null && $peek['value'] === '(') {
  2306.                     return $this->FunctionDeclaration();
  2307.                 }
  2308.                 if ($peek !== null && $peek['value'] === '.') {
  2309.                     return $this->SingleValuedPathExpression();
  2310.                 }
  2311.                 if (isset($this->queryComponents[$this->lexer->lookahead['value']]['resultVariable'])) {
  2312.                     return $this->ResultVariable();
  2313.                 }
  2314.                 return $this->StateFieldPathExpression();
  2315.             case Lexer::T_INPUT_PARAMETER:
  2316.                 return $this->InputParameter();
  2317.             default:
  2318.                 $peek $this->lexer->glimpse();
  2319.                 if ($peek !== null && $peek['value'] === '(') {
  2320.                     return $this->FunctionDeclaration();
  2321.                 }
  2322.                 return $this->Literal();
  2323.         }
  2324.     }
  2325.     /**
  2326.      * StringExpression ::= StringPrimary | ResultVariable | "(" Subselect ")"
  2327.      *
  2328.      * @return \Doctrine\ORM\Query\AST\Subselect |
  2329.      *         string
  2330.      */
  2331.     public function StringExpression()
  2332.     {
  2333.         $peek $this->lexer->glimpse();
  2334.         // Subselect
  2335.         if ($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS) && $peek['type'] === Lexer::T_SELECT) {
  2336.             $this->match(Lexer::T_OPEN_PARENTHESIS);
  2337.             $expr $this->Subselect();
  2338.             $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2339.             return $expr;
  2340.         }
  2341.         // ResultVariable (string)
  2342.         if ($this->lexer->isNextToken(Lexer::T_IDENTIFIER) &&
  2343.             isset($this->queryComponents[$this->lexer->lookahead['value']]['resultVariable'])) {
  2344.             return $this->ResultVariable();
  2345.         }
  2346.         return $this->StringPrimary();
  2347.     }
  2348.     /**
  2349.      * StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression | CaseExpression
  2350.      */
  2351.     public function StringPrimary()
  2352.     {
  2353.         $lookaheadType $this->lexer->lookahead['type'];
  2354.         switch ($lookaheadType) {
  2355.             case Lexer::T_IDENTIFIER:
  2356.                 $peek $this->lexer->glimpse();
  2357.                 if ($peek['value'] == '.') {
  2358.                     return $this->StateFieldPathExpression();
  2359.                 }
  2360.                 if ($peek['value'] == '(') {
  2361.                     // do NOT directly go to FunctionsReturningString() because it doesn't check for custom functions.
  2362.                     return $this->FunctionDeclaration();
  2363.                 }
  2364.                 $this->syntaxError("'.' or '('");
  2365.                 break;
  2366.             case Lexer::T_STRING:
  2367.                 $this->match(Lexer::T_STRING);
  2368.                 return new AST\Literal(AST\Literal::STRING$this->lexer->token['value']);
  2369.             case Lexer::T_INPUT_PARAMETER:
  2370.                 return $this->InputParameter();
  2371.             case Lexer::T_CASE:
  2372.             case Lexer::T_COALESCE:
  2373.             case Lexer::T_NULLIF:
  2374.                 return $this->CaseExpression();
  2375.             default:
  2376.                 if ($this->isAggregateFunction($lookaheadType)) {
  2377.                     return $this->AggregateExpression();
  2378.                 }
  2379.         }
  2380.         $this->syntaxError(
  2381.             'StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression'
  2382.         );
  2383.     }
  2384.     /**
  2385.      * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression
  2386.      *
  2387.      * @return \Doctrine\ORM\Query\AST\PathExpression |
  2388.      *         \Doctrine\ORM\Query\AST\SimpleEntityExpression
  2389.      */
  2390.     public function EntityExpression()
  2391.     {
  2392.         $glimpse $this->lexer->glimpse();
  2393.         if ($this->lexer->isNextToken(Lexer::T_IDENTIFIER) && $glimpse['value'] === '.') {
  2394.             return $this->SingleValuedAssociationPathExpression();
  2395.         }
  2396.         return $this->SimpleEntityExpression();
  2397.     }
  2398.     /**
  2399.      * SimpleEntityExpression ::= IdentificationVariable | InputParameter
  2400.      *
  2401.      * @return string | \Doctrine\ORM\Query\AST\InputParameter
  2402.      */
  2403.     public function SimpleEntityExpression()
  2404.     {
  2405.         if ($this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
  2406.             return $this->InputParameter();
  2407.         }
  2408.         return $this->StateFieldPathExpression();
  2409.     }
  2410.     /**
  2411.      * AggregateExpression ::=
  2412.      *  ("AVG" | "MAX" | "MIN" | "SUM" | "COUNT") "(" ["DISTINCT"] SimpleArithmeticExpression ")"
  2413.      *
  2414.      * @return \Doctrine\ORM\Query\AST\AggregateExpression
  2415.      */
  2416.     public function AggregateExpression()
  2417.     {
  2418.         $lookaheadType $this->lexer->lookahead['type'];
  2419.         $isDistinct false;
  2420.         if ( ! in_array($lookaheadType, [Lexer::T_COUNTLexer::T_AVGLexer::T_MAXLexer::T_MINLexer::T_SUM])) {
  2421.             $this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT');
  2422.         }
  2423.         $this->match($lookaheadType);
  2424.         $functionName $this->lexer->token['value'];
  2425.         $this->match(Lexer::T_OPEN_PARENTHESIS);
  2426.         if ($this->lexer->isNextToken(Lexer::T_DISTINCT)) {
  2427.             $this->match(Lexer::T_DISTINCT);
  2428.             $isDistinct true;
  2429.         }
  2430.         $pathExp $this->SimpleArithmeticExpression();
  2431.         $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2432.         return new AST\AggregateExpression($functionName$pathExp$isDistinct);
  2433.     }
  2434.     /**
  2435.      * QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")"
  2436.      *
  2437.      * @return \Doctrine\ORM\Query\AST\QuantifiedExpression
  2438.      */
  2439.     public function QuantifiedExpression()
  2440.     {
  2441.         $lookaheadType $this->lexer->lookahead['type'];
  2442.         $value $this->lexer->lookahead['value'];
  2443.         if ( ! in_array($lookaheadType, [Lexer::T_ALLLexer::T_ANYLexer::T_SOME])) {
  2444.             $this->syntaxError('ALL, ANY or SOME');
  2445.         }
  2446.         $this->match($lookaheadType);
  2447.         $this->match(Lexer::T_OPEN_PARENTHESIS);
  2448.         $qExpr = new AST\QuantifiedExpression($this->Subselect());
  2449.         $qExpr->type $value;
  2450.         $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2451.         return $qExpr;
  2452.     }
  2453.     /**
  2454.      * BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression
  2455.      *
  2456.      * @return \Doctrine\ORM\Query\AST\BetweenExpression
  2457.      */
  2458.     public function BetweenExpression()
  2459.     {
  2460.         $not false;
  2461.         $arithExpr1 $this->ArithmeticExpression();
  2462.         if ($this->lexer->isNextToken(Lexer::T_NOT)) {
  2463.             $this->match(Lexer::T_NOT);
  2464.             $not true;
  2465.         }
  2466.         $this->match(Lexer::T_BETWEEN);
  2467.         $arithExpr2 $this->ArithmeticExpression();
  2468.         $this->match(Lexer::T_AND);
  2469.         $arithExpr3 $this->ArithmeticExpression();
  2470.         $betweenExpr = new AST\BetweenExpression($arithExpr1$arithExpr2$arithExpr3);
  2471.         $betweenExpr->not $not;
  2472.         return $betweenExpr;
  2473.     }
  2474.     /**
  2475.      * ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression )
  2476.      *
  2477.      * @return \Doctrine\ORM\Query\AST\ComparisonExpression
  2478.      */
  2479.     public function ComparisonExpression()
  2480.     {
  2481.         $this->lexer->glimpse();
  2482.         $leftExpr  $this->ArithmeticExpression();
  2483.         $operator  $this->ComparisonOperator();
  2484.         $rightExpr = ($this->isNextAllAnySome())
  2485.             ? $this->QuantifiedExpression()
  2486.             : $this->ArithmeticExpression();
  2487.         return new AST\ComparisonExpression($leftExpr$operator$rightExpr);
  2488.     }
  2489.     /**
  2490.      * InExpression ::= SingleValuedPathExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")"
  2491.      *
  2492.      * @return \Doctrine\ORM\Query\AST\InExpression
  2493.      */
  2494.     public function InExpression()
  2495.     {
  2496.         $inExpression = new AST\InExpression($this->ArithmeticExpression());
  2497.         if ($this->lexer->isNextToken(Lexer::T_NOT)) {
  2498.             $this->match(Lexer::T_NOT);
  2499.             $inExpression->not true;
  2500.         }
  2501.         $this->match(Lexer::T_IN);
  2502.         $this->match(Lexer::T_OPEN_PARENTHESIS);
  2503.         if ($this->lexer->isNextToken(Lexer::T_SELECT)) {
  2504.             $inExpression->subselect $this->Subselect();
  2505.         } else {
  2506.             $literals = [];
  2507.             $literals[] = $this->InParameter();
  2508.             while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
  2509.                 $this->match(Lexer::T_COMMA);
  2510.                 $literals[] = $this->InParameter();
  2511.             }
  2512.             $inExpression->literals $literals;
  2513.         }
  2514.         $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2515.         return $inExpression;
  2516.     }
  2517.     /**
  2518.      * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (InstanceOfParameter | "(" InstanceOfParameter {"," InstanceOfParameter}* ")")
  2519.      *
  2520.      * @return \Doctrine\ORM\Query\AST\InstanceOfExpression
  2521.      */
  2522.     public function InstanceOfExpression()
  2523.     {
  2524.         $instanceOfExpression = new AST\InstanceOfExpression($this->IdentificationVariable());
  2525.         if ($this->lexer->isNextToken(Lexer::T_NOT)) {
  2526.             $this->match(Lexer::T_NOT);
  2527.             $instanceOfExpression->not true;
  2528.         }
  2529.         $this->match(Lexer::T_INSTANCE);
  2530.         $this->match(Lexer::T_OF);
  2531.         $exprValues = [];
  2532.         if ($this->lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
  2533.             $this->match(Lexer::T_OPEN_PARENTHESIS);
  2534.             $exprValues[] = $this->InstanceOfParameter();
  2535.             while ($this->lexer->isNextToken(Lexer::T_COMMA)) {
  2536.                 $this->match(Lexer::T_COMMA);
  2537.                 $exprValues[] = $this->InstanceOfParameter();
  2538.             }
  2539.             $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2540.             $instanceOfExpression->value $exprValues;
  2541.             return $instanceOfExpression;
  2542.         }
  2543.         $exprValues[] = $this->InstanceOfParameter();
  2544.         $instanceOfExpression->value $exprValues;
  2545.         return $instanceOfExpression;
  2546.     }
  2547.     /**
  2548.      * InstanceOfParameter ::= AbstractSchemaName | InputParameter
  2549.      *
  2550.      * @return mixed
  2551.      */
  2552.     public function InstanceOfParameter()
  2553.     {
  2554.         if ($this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
  2555.             $this->match(Lexer::T_INPUT_PARAMETER);
  2556.             return new AST\InputParameter($this->lexer->token['value']);
  2557.         }
  2558.         $abstractSchemaName $this->AbstractSchemaName();
  2559.         $this->validateAbstractSchemaName($abstractSchemaName);
  2560.         return $abstractSchemaName;
  2561.     }
  2562.     /**
  2563.      * LikeExpression ::= StringExpression ["NOT"] "LIKE" StringPrimary ["ESCAPE" char]
  2564.      *
  2565.      * @return \Doctrine\ORM\Query\AST\LikeExpression
  2566.      */
  2567.     public function LikeExpression()
  2568.     {
  2569.         $stringExpr $this->StringExpression();
  2570.         $not false;
  2571.         if ($this->lexer->isNextToken(Lexer::T_NOT)) {
  2572.             $this->match(Lexer::T_NOT);
  2573.             $not true;
  2574.         }
  2575.         $this->match(Lexer::T_LIKE);
  2576.         if ($this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
  2577.             $this->match(Lexer::T_INPUT_PARAMETER);
  2578.             $stringPattern = new AST\InputParameter($this->lexer->token['value']);
  2579.         } else {
  2580.             $stringPattern $this->StringPrimary();
  2581.         }
  2582.         $escapeChar null;
  2583.         if ($this->lexer->lookahead !== null && $this->lexer->lookahead['type'] === Lexer::T_ESCAPE) {
  2584.             $this->match(Lexer::T_ESCAPE);
  2585.             $this->match(Lexer::T_STRING);
  2586.             $escapeChar = new AST\Literal(AST\Literal::STRING$this->lexer->token['value']);
  2587.         }
  2588.         $likeExpr = new AST\LikeExpression($stringExpr$stringPattern$escapeChar);
  2589.         $likeExpr->not $not;
  2590.         return $likeExpr;
  2591.     }
  2592.     /**
  2593.      * NullComparisonExpression ::= (InputParameter | NullIfExpression | CoalesceExpression | AggregateExpression | FunctionDeclaration | IdentificationVariable | SingleValuedPathExpression | ResultVariable) "IS" ["NOT"] "NULL"
  2594.      *
  2595.      * @return \Doctrine\ORM\Query\AST\NullComparisonExpression
  2596.      */
  2597.     public function NullComparisonExpression()
  2598.     {
  2599.         switch (true) {
  2600.             case $this->lexer->isNextToken(Lexer::T_INPUT_PARAMETER):
  2601.                 $this->match(Lexer::T_INPUT_PARAMETER);
  2602.                 $expr = new AST\InputParameter($this->lexer->token['value']);
  2603.                 break;
  2604.             case $this->lexer->isNextToken(Lexer::T_NULLIF):
  2605.                 $expr $this->NullIfExpression();
  2606.                 break;
  2607.             case $this->lexer->isNextToken(Lexer::T_COALESCE):
  2608.                 $expr $this->CoalesceExpression();
  2609.                 break;
  2610.             case $this->isFunction():
  2611.                 $expr $this->FunctionDeclaration();
  2612.                 break;
  2613.             default:
  2614.                 // We need to check if we are in a IdentificationVariable or SingleValuedPathExpression
  2615.                 $glimpse $this->lexer->glimpse();
  2616.                 if ($glimpse['type'] === Lexer::T_DOT) {
  2617.                     $expr $this->SingleValuedPathExpression();
  2618.                     // Leave switch statement
  2619.                     break;
  2620.                 }
  2621.                 $lookaheadValue $this->lexer->lookahead['value'];
  2622.                 // Validate existing component
  2623.                 if ( ! isset($this->queryComponents[$lookaheadValue])) {
  2624.                     $this->semanticalError('Cannot add having condition on undefined result variable.');
  2625.                 }
  2626.                 // Validate SingleValuedPathExpression (ie.: "product")
  2627.                 if (isset($this->queryComponents[$lookaheadValue]['metadata'])) {
  2628.                     $expr $this->SingleValuedPathExpression();
  2629.                     break;
  2630.                 }
  2631.                 // Validating ResultVariable
  2632.                 if ( ! isset($this->queryComponents[$lookaheadValue]['resultVariable'])) {
  2633.                     $this->semanticalError('Cannot add having condition on a non result variable.');
  2634.                 }
  2635.                 $expr $this->ResultVariable();
  2636.                 break;
  2637.         }
  2638.         $nullCompExpr = new AST\NullComparisonExpression($expr);
  2639.         $this->match(Lexer::T_IS);
  2640.         if ($this->lexer->isNextToken(Lexer::T_NOT)) {
  2641.             $this->match(Lexer::T_NOT);
  2642.             $nullCompExpr->not true;
  2643.         }
  2644.         $this->match(Lexer::T_NULL);
  2645.         return $nullCompExpr;
  2646.     }
  2647.     /**
  2648.      * ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")"
  2649.      *
  2650.      * @return \Doctrine\ORM\Query\AST\ExistsExpression
  2651.      */
  2652.     public function ExistsExpression()
  2653.     {
  2654.         $not false;
  2655.         if ($this->lexer->isNextToken(Lexer::T_NOT)) {
  2656.             $this->match(Lexer::T_NOT);
  2657.             $not true;
  2658.         }
  2659.         $this->match(Lexer::T_EXISTS);
  2660.         $this->match(Lexer::T_OPEN_PARENTHESIS);
  2661.         $existsExpression = new AST\ExistsExpression($this->Subselect());
  2662.         $existsExpression->not $not;
  2663.         $this->match(Lexer::T_CLOSE_PARENTHESIS);
  2664.         return $existsExpression;
  2665.     }
  2666.     /**
  2667.      * ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!="
  2668.      *
  2669.      * @return string
  2670.      */
  2671.     public function ComparisonOperator()
  2672.     {
  2673.         switch ($this->lexer->lookahead['value']) {
  2674.             case '=':
  2675.                 $this->match(Lexer::T_EQUALS);
  2676.                 return '=';
  2677.             case '<':
  2678.                 $this->match(Lexer::T_LOWER_THAN);
  2679.                 $operator '<';
  2680.                 if ($this->lexer->isNextToken(Lexer::T_EQUALS)) {
  2681.                     $this->match(Lexer::T_EQUALS);
  2682.                     $operator .= '=';
  2683.                 } else if ($this->lexer->isNextToken(Lexer::T_GREATER_THAN)) {
  2684.                     $this->match(Lexer::T_GREATER_THAN);
  2685.                     $operator .= '>';
  2686.                 }
  2687.                 return $operator;
  2688.             case '>':
  2689.                 $this->match(Lexer::T_GREATER_THAN);
  2690.                 $operator '>';
  2691.                 if ($this->lexer->isNextToken(Lexer::T_EQUALS)) {
  2692.                     $this->match(Lexer::T_EQUALS);
  2693.                     $operator .= '=';
  2694.                 }
  2695.                 return $operator;
  2696.             case '!':
  2697.                 $this->match(Lexer::T_NEGATE);
  2698.                 $this->match(Lexer::T_EQUALS);
  2699.                 return '<>';
  2700.             default:
  2701.                 $this->syntaxError('=, <, <=, <>, >, >=, !=');
  2702.         }
  2703.     }
  2704.     /**
  2705.      * FunctionDeclaration ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDatetime
  2706.      *
  2707.      * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode
  2708.      */
  2709.     public function FunctionDeclaration()
  2710.     {
  2711.         $token $this->lexer->lookahead;
  2712.         $funcName strtolower($token['value']);
  2713.         $customFunctionDeclaration $this->CustomFunctionDeclaration();
  2714.         // Check for custom functions functions first!
  2715.         switch (true) {
  2716.             case $customFunctionDeclaration !== null:
  2717.                 return $customFunctionDeclaration;
  2718.             case (isset(self::$_STRING_FUNCTIONS[$funcName])):
  2719.                 return $this->FunctionsReturningStrings();
  2720.             case (isset(self::$_NUMERIC_FUNCTIONS[$funcName])):
  2721.                 return $this->FunctionsReturningNumerics();
  2722.             case (isset(self::$_DATETIME_FUNCTIONS[$funcName])):
  2723.                 return $this->FunctionsReturningDatetime();
  2724.             default:
  2725.                 $this->syntaxError('known function'$token);
  2726.         }
  2727.     }
  2728.     /**
  2729.      * Helper function for FunctionDeclaration grammar rule.
  2730.      *
  2731.      * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode
  2732.      */
  2733.     private function CustomFunctionDeclaration()
  2734.     {
  2735.         $token $this->lexer->lookahead;
  2736.         $funcName strtolower($token['value']);
  2737.         // Check for custom functions afterwards
  2738.         $config $this->em->getConfiguration();
  2739.         switch (true) {
  2740.             case ($config->getCustomStringFunction($funcName) !== null):
  2741.                 return $this->CustomFunctionsReturningStrings();
  2742.             case ($config->getCustomNumericFunction($funcName) !== null):
  2743.                 return $this->CustomFunctionsReturningNumerics();
  2744.             case ($config->getCustomDatetimeFunction($funcName) !== null):
  2745.                 return $this->CustomFunctionsReturningDatetime();
  2746.             default:
  2747.                 return null;
  2748.         }
  2749.     }
  2750.     /**
  2751.      * FunctionsReturningNumerics ::=
  2752.      *      "LENGTH" "(" StringPrimary ")" |
  2753.      *      "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" |
  2754.      *      "ABS" "(" SimpleArithmeticExpression ")" |
  2755.      *      "SQRT" "(" SimpleArithmeticExpression ")" |
  2756.      *      "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
  2757.      *      "SIZE" "(" CollectionValuedPathExpression ")" |
  2758.      *      "DATE_DIFF" "(" ArithmeticPrimary "," ArithmeticPrimary ")" |
  2759.      *      "BIT_AND" "(" ArithmeticPrimary "," ArithmeticPrimary ")" |
  2760.      *      "BIT_OR" "(" ArithmeticPrimary "," ArithmeticPrimary ")"
  2761.      *
  2762.      * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode
  2763.      */
  2764.     public function FunctionsReturningNumerics()
  2765.     {
  2766.         $funcNameLower strtolower($this->lexer->lookahead['value']);
  2767.         $funcClass     self::$_NUMERIC_FUNCTIONS[$funcNameLower];
  2768.         $function = new $funcClass($funcNameLower);
  2769.         $function->parse($this);
  2770.         return $function;
  2771.     }
  2772.     /**
  2773.      * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode
  2774.      */
  2775.     public function CustomFunctionsReturningNumerics()
  2776.     {
  2777.         // getCustomNumericFunction is case-insensitive
  2778.         $functionName  strtolower($this->lexer->lookahead['value']);
  2779.         $functionClass $this->em->getConfiguration()->getCustomNumericFunction($functionName);
  2780.         $function is_string($functionClass)
  2781.             ? new $functionClass($functionName)
  2782.             : call_user_func($functionClass$functionName);
  2783.         $function->parse($this);
  2784.         return $function;
  2785.     }
  2786.     /**
  2787.      * FunctionsReturningDateTime ::=
  2788.      *     "CURRENT_DATE" |
  2789.      *     "CURRENT_TIME" |
  2790.      *     "CURRENT_TIMESTAMP" |
  2791.      *     "DATE_ADD" "(" ArithmeticPrimary "," ArithmeticPrimary "," StringPrimary ")" |
  2792.      *     "DATE_SUB" "(" ArithmeticPrimary "," ArithmeticPrimary "," StringPrimary ")"
  2793.      *
  2794.      * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode
  2795.      */
  2796.     public function FunctionsReturningDatetime()
  2797.     {
  2798.         $funcNameLower strtolower($this->lexer->lookahead['value']);
  2799.         $funcClass     self::$_DATETIME_FUNCTIONS[$funcNameLower];
  2800.         $function = new $funcClass($funcNameLower);
  2801.         $function->parse($this);
  2802.         return $function;
  2803.     }
  2804.     /**
  2805.      * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode
  2806.      */
  2807.     public function CustomFunctionsReturningDatetime()
  2808.     {
  2809.         // getCustomDatetimeFunction is case-insensitive
  2810.         $functionName  $this->lexer->lookahead['value'];
  2811.         $functionClass $this->em->getConfiguration()->getCustomDatetimeFunction($functionName);
  2812.         $function is_string($functionClass)
  2813.             ? new $functionClass($functionName)
  2814.             : call_user_func($functionClass$functionName);
  2815.         $function->parse($this);
  2816.         return $function;
  2817.     }
  2818.     /**
  2819.      * FunctionsReturningStrings ::=
  2820.      *   "CONCAT" "(" StringPrimary "," StringPrimary {"," StringPrimary}* ")" |
  2821.      *   "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
  2822.      *   "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" |
  2823.      *   "LOWER" "(" StringPrimary ")" |
  2824.      *   "UPPER" "(" StringPrimary ")" |
  2825.      *   "IDENTITY" "(" SingleValuedAssociationPathExpression {"," string} ")"
  2826.      *
  2827.      * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode
  2828.      */
  2829.     public function FunctionsReturningStrings()
  2830.     {
  2831.         $funcNameLower strtolower($this->lexer->lookahead['value']);
  2832.         $funcClass     self::$_STRING_FUNCTIONS[$funcNameLower];
  2833.         $function = new $funcClass($funcNameLower);
  2834.         $function->parse($this);
  2835.         return $function;
  2836.     }
  2837.     /**
  2838.      * @return \Doctrine\ORM\Query\AST\Functions\FunctionNode
  2839.      */
  2840.     public function CustomFunctionsReturningStrings()
  2841.     {
  2842.         // getCustomStringFunction is case-insensitive
  2843.         $functionName  $this->lexer->lookahead['value'];
  2844.         $functionClass $this->em->getConfiguration()->getCustomStringFunction($functionName);
  2845.         $function is_string($functionClass)
  2846.             ? new $functionClass($functionName)
  2847.             : call_user_func($functionClass$functionName);
  2848.         $function->parse($this);
  2849.         return $function;
  2850.     }
  2851. }