| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868 | 
							- <?php
 - /*
 -  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 -  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 -  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 -  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 -  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 -  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 -  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 -  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 -  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 -  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 -  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 -  *
 -  * This software consists of voluntary contributions made by many individuals
 -  * and is licensed under the LGPL. For more information, see
 -  * <http://www.doctrine-project.org>.
 -  */
 - 
 - namespace Doctrine\ORM\Query;
 - 
 - use Doctrine\ORM\Query;
 - use Doctrine\ORM\Mapping\ClassMetadata;
 - 
 - /**
 -  * An LL(*) recursive-descent parser for the context-free grammar of the Doctrine Query Language.
 -  * Parses a DQL query, reports any errors in it, and generates an AST.
 -  *
 -  * @since   2.0
 -  * @author  Guilherme Blanco <guilhermeblanco@hotmail.com>
 -  * @author  Jonathan Wage <jonwage@gmail.com>
 -  * @author  Roman Borschel <roman@code-factory.org>
 -  * @author  Janne Vanhala <jpvanhal@cc.hut.fi>
 -  */
 - class Parser
 - {
 -     /** READ-ONLY: Maps BUILT-IN string function names to AST class names. */
 -     private static $_STRING_FUNCTIONS = array(
 -         'concat'    => 'Doctrine\ORM\Query\AST\Functions\ConcatFunction',
 -         'substring' => 'Doctrine\ORM\Query\AST\Functions\SubstringFunction',
 -         'trim'      => 'Doctrine\ORM\Query\AST\Functions\TrimFunction',
 -         'lower'     => 'Doctrine\ORM\Query\AST\Functions\LowerFunction',
 -         'upper'     => 'Doctrine\ORM\Query\AST\Functions\UpperFunction'
 -     );
 - 
 -     /** READ-ONLY: Maps BUILT-IN numeric function names to AST class names. */
 -     private static $_NUMERIC_FUNCTIONS = array(
 -         'length'    => 'Doctrine\ORM\Query\AST\Functions\LengthFunction',
 -         'locate'    => 'Doctrine\ORM\Query\AST\Functions\LocateFunction',
 -         'abs'       => 'Doctrine\ORM\Query\AST\Functions\AbsFunction',
 -         'sqrt'      => 'Doctrine\ORM\Query\AST\Functions\SqrtFunction',
 -         'mod'       => 'Doctrine\ORM\Query\AST\Functions\ModFunction',
 -         'size'      => 'Doctrine\ORM\Query\AST\Functions\SizeFunction',
 -         'date_diff' => 'Doctrine\ORM\Query\AST\Functions\DateDiffFunction',
 -     );
 - 
 -     /** READ-ONLY: Maps BUILT-IN datetime function names to AST class names. */
 -     private static $_DATETIME_FUNCTIONS = array(
 -         'current_date'      => 'Doctrine\ORM\Query\AST\Functions\CurrentDateFunction',
 -         'current_time'      => 'Doctrine\ORM\Query\AST\Functions\CurrentTimeFunction',
 -         'current_timestamp' => 'Doctrine\ORM\Query\AST\Functions\CurrentTimestampFunction',
 -         'date_add'          => 'Doctrine\ORM\Query\AST\Functions\DateAddFunction',
 -         'date_sub'          => 'Doctrine\ORM\Query\AST\Functions\DateSubFunction',
 -     );
 - 
 -     /**
 -      * Expressions that were encountered during parsing of identifiers and expressions
 -      * and still need to be validated.
 -      */
 -     private $_deferredIdentificationVariables = array();
 -     private $_deferredPartialObjectExpressions = array();
 -     private $_deferredPathExpressions = array();
 -     private $_deferredResultVariables = array();
 - 
 -     /**
 -      * The lexer.
 -      *
 -      * @var \Doctrine\ORM\Query\Lexer
 -      */
 -     private $_lexer;
 - 
 -     /**
 -      * The parser result.
 -      *
 -      * @var \Doctrine\ORM\Query\ParserResult
 -      */
 -     private $_parserResult;
 - 
 -     /**
 -      * The EntityManager.
 -      *
 -      * @var EnityManager
 -      */
 -     private $_em;
 - 
 -     /**
 -      * The Query to parse.
 -      *
 -      * @var Query
 -      */
 -     private $_query;
 - 
 -     /**
 -      * Map of declared query components in the parsed query.
 -      *
 -      * @var array
 -      */
 -     private $_queryComponents = array();
 - 
 -     /**
 -      * Keeps the nesting level of defined ResultVariables
 -      *
 -      * @var integer
 -      */
 -     private $_nestingLevel = 0;
 - 
 -     /**
 -      * Any additional custom tree walkers that modify the AST.
 -      *
 -      * @var array
 -      */
 -     private $_customTreeWalkers = array();
 - 
 -     /**
 -      * The custom last tree walker, if any, that is responsible for producing the output.
 -      *
 -      * @var TreeWalker
 -      */
 -     private $_customOutputWalker;
 - 
 -     /**
 -      * @var array
 -      */
 -     private $_identVariableExpressions = array();
 - 
 -     /**
 -      * Creates a new query parser object.
 -      *
 -      * @param Query $query The Query to parse.
 -      */
 -     public function __construct(Query $query)
 -     {
 -         $this->_query = $query;
 -         $this->_em = $query->getEntityManager();
 -         $this->_lexer = new Lexer($query->getDql());
 -         $this->_parserResult = new ParserResult();
 -     }
 - 
 -     /**
 -      * Sets a custom tree walker that produces output.
 -      * This tree walker will be run last over the AST, after any other walkers.
 -      *
 -      * @param string $className
 -      */
 -     public function setCustomOutputTreeWalker($className)
 -     {
 -         $this->_customOutputWalker = $className;
 -     }
 - 
 -     /**
 -      * Adds a custom tree walker for modifying the AST.
 -      *
 -      * @param string $className
 -      */
 -     public function addCustomTreeWalker($className)
 -     {
 -         $this->_customTreeWalkers[] = $className;
 -     }
 - 
 -     /**
 -      * Gets the lexer used by the parser.
 -      *
 -      * @return \Doctrine\ORM\Query\Lexer
 -      */
 -     public function getLexer()
 -     {
 -         return $this->_lexer;
 -     }
 - 
 -     /**
 -      * Gets the ParserResult that is being filled with information during parsing.
 -      *
 -      * @return \Doctrine\ORM\Query\ParserResult
 -      */
 -     public function getParserResult()
 -     {
 -         return $this->_parserResult;
 -     }
 - 
 -     /**
 -      * Gets the EntityManager used by the parser.
 -      *
 -      * @return EntityManager
 -      */
 -     public function getEntityManager()
 -     {
 -         return $this->_em;
 -     }
 - 
 -     /**
 -      * Parse and build AST for the given Query.
 -      *
 -      * @return \Doctrine\ORM\Query\AST\SelectStatement |
 -      *         \Doctrine\ORM\Query\AST\UpdateStatement |
 -      *         \Doctrine\ORM\Query\AST\DeleteStatement
 -      */
 -     public function getAST()
 -     {
 -         // Parse & build AST
 -         $AST = $this->QueryLanguage();
 - 
 -         // Process any deferred validations of some nodes in the AST.
 -         // This also allows post-processing of the AST for modification purposes.
 -         $this->_processDeferredIdentificationVariables();
 - 
 -         if ($this->_deferredPartialObjectExpressions) {
 -             $this->_processDeferredPartialObjectExpressions();
 -         }
 - 
 -         if ($this->_deferredPathExpressions) {
 -             $this->_processDeferredPathExpressions($AST);
 -         }
 - 
 -         if ($this->_deferredResultVariables) {
 -             $this->_processDeferredResultVariables();
 -         }
 - 
 -         return $AST;
 -     }
 - 
 -     /**
 -      * Attempts to match the given token with the current lookahead token.
 -      *
 -      * If they match, updates the lookahead token; otherwise raises a syntax
 -      * error.
 -      *
 -      * @param int token type
 -      * @return void
 -      * @throws QueryException If the tokens dont match.
 -      */
 -     public function match($token)
 -     {
 -         // short-circuit on first condition, usually types match
 -         if ($this->_lexer->lookahead['type'] !== $token &&
 -                 $token !== Lexer::T_IDENTIFIER &&
 -                 $this->_lexer->lookahead['type'] <= Lexer::T_IDENTIFIER
 -          ) {
 -             $this->syntaxError($this->_lexer->getLiteral($token));
 -         }
 - 
 -         $this->_lexer->moveNext();
 -     }
 - 
 -     /**
 -      * Free this parser enabling it to be reused
 -      *
 -      * @param boolean $deep     Whether to clean peek and reset errors
 -      * @param integer $position Position to reset
 -      */
 -     public function free($deep = false, $position = 0)
 -     {
 -         // WARNING! Use this method with care. It resets the scanner!
 -         $this->_lexer->resetPosition($position);
 - 
 -         // Deep = true cleans peek and also any previously defined errors
 -         if ($deep) {
 -             $this->_lexer->resetPeek();
 -         }
 - 
 -         $this->_lexer->token = null;
 -         $this->_lexer->lookahead = null;
 -     }
 - 
 -     /**
 -      * Parses a query string.
 -      *
 -      * @return ParserResult
 -      */
 -     public function parse()
 -     {
 -         $AST = $this->getAST();
 - 
 -         $this->fixIdentificationVariableOrder($AST);
 -         $this->assertSelectEntityRootAliasRequirement();
 - 
 -         if (($customWalkers = $this->_query->getHint(Query::HINT_CUSTOM_TREE_WALKERS)) !== false) {
 -             $this->_customTreeWalkers = $customWalkers;
 -         }
 - 
 -         if (($customOutputWalker = $this->_query->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER)) !== false) {
 -             $this->_customOutputWalker = $customOutputWalker;
 -         }
 - 
 -         // Run any custom tree walkers over the AST
 -         if ($this->_customTreeWalkers) {
 -             $treeWalkerChain = new TreeWalkerChain($this->_query, $this->_parserResult, $this->_queryComponents);
 - 
 -             foreach ($this->_customTreeWalkers as $walker) {
 -                 $treeWalkerChain->addTreeWalker($walker);
 -             }
 - 
 -             if ($AST instanceof AST\SelectStatement) {
 -                 $treeWalkerChain->walkSelectStatement($AST);
 -             } else if ($AST instanceof AST\UpdateStatement) {
 -                 $treeWalkerChain->walkUpdateStatement($AST);
 -             } else {
 -                 $treeWalkerChain->walkDeleteStatement($AST);
 -             }
 -         }
 - 
 -         if ($this->_customOutputWalker) {
 -             $outputWalker = new $this->_customOutputWalker(
 -                 $this->_query, $this->_parserResult, $this->_queryComponents
 -             );
 -         } else {
 -             $outputWalker = new SqlWalker(
 -                 $this->_query, $this->_parserResult, $this->_queryComponents
 -             );
 -         }
 - 
 -         // Assign an SQL executor to the parser result
 -         $this->_parserResult->setSqlExecutor($outputWalker->getExecutor($AST));
 - 
 -         return $this->_parserResult;
 -     }
 -     
 -     private function assertSelectEntityRootAliasRequirement()
 -     {
 -         if ( count($this->_identVariableExpressions) > 0) {
 -             $foundRootEntity = false;
 -             foreach ($this->_identVariableExpressions AS $dqlAlias => $expr) {
 -                 if (isset($this->_queryComponents[$dqlAlias]) && $this->_queryComponents[$dqlAlias]['parent'] === null) {
 -                     $foundRootEntity = true;
 -                 }
 -             }
 -             
 -             if (!$foundRootEntity) {
 -                 $this->semanticalError('Cannot select entity through identification variables without choosing at least one root entity alias.');
 -             }
 -         }
 -     }
 -     
 -     /**
 -      * Fix order of identification variables.
 -      * 
 -      * They have to appear in the select clause in the same order as the
 -      * declarations (from ... x join ... y join ... z ...) appear in the query
 -      * as the hydration process relies on that order for proper operation.
 -      * 
 -      * @param AST\SelectStatement|AST\DeleteStatement|AST\UpdateStatement $AST
 -      * @return void
 -      */
 -     private function fixIdentificationVariableOrder($AST)
 -     {
 -         if ( count($this->_identVariableExpressions) > 1) {
 -             foreach ($this->_queryComponents as $dqlAlias => $qComp) {
 -                 if (isset($this->_identVariableExpressions[$dqlAlias])) {
 -                     $expr = $this->_identVariableExpressions[$dqlAlias];
 -                     $key = array_search($expr, $AST->selectClause->selectExpressions);
 -                     unset($AST->selectClause->selectExpressions[$key]);
 -                     $AST->selectClause->selectExpressions[] = $expr;
 -                 }
 -             }
 -         }
 -     }
 - 
 -     /**
 -      * Generates a new syntax error.
 -      *
 -      * @param string $expected Expected string.
 -      * @param array $token Got token.
 -      *
 -      * @throws \Doctrine\ORM\Query\QueryException
 -      */
 -     public function syntaxError($expected = '', $token = null)
 -     {
 -         if ($token === null) {
 -             $token = $this->_lexer->lookahead;
 -         }
 - 
 -         $tokenPos = (isset($token['position'])) ? $token['position'] : '-1';
 -         $message  = "line 0, col {$tokenPos}: Error: ";
 - 
 -         if ($expected !== '') {
 -             $message .= "Expected {$expected}, got ";
 -         } else {
 -             $message .= 'Unexpected ';
 -         }
 - 
 -         if ($this->_lexer->lookahead === null) {
 -             $message .= 'end of string.';
 -         } else {
 -             $message .= "'{$token['value']}'";
 -         }
 - 
 -         throw QueryException::syntaxError($message);
 -     }
 - 
 -     /**
 -      * Generates a new semantical error.
 -      *
 -      * @param string $message Optional message.
 -      * @param array $token Optional token.
 -      *
 -      * @throws \Doctrine\ORM\Query\QueryException
 -      */
 -     public function semanticalError($message = '', $token = null)
 -     {
 -         if ($token === null) {
 -             $token = $this->_lexer->lookahead;
 -         }
 - 
 -         // Minimum exposed chars ahead of token
 -         $distance = 12;
 - 
 -         // Find a position of a final word to display in error string
 -         $dql = $this->_query->getDql();
 -         $length = strlen($dql);
 -         $pos = $token['position'] + $distance;
 -         $pos = strpos($dql, ' ', ($length > $pos) ? $pos : $length);
 -         $length = ($pos !== false) ? $pos - $token['position'] : $distance;
 - 
 -         // Building informative message
 -         $message = 'line 0, col ' . (
 -             (isset($token['position']) && $token['position'] > 0) ? $token['position'] : '-1'
 -         ) . " near '" . substr($dql, $token['position'], $length) . "': Error: " . $message;
 - 
 -         throw \Doctrine\ORM\Query\QueryException::semanticalError($message);
 -     }
 - 
 -     /**
 -      * Peeks beyond the specified token and returns the first token after that one.
 -      *
 -      * @param array $token
 -      * @return array
 -      */
 -     private function _peekBeyond($token)
 -     {
 -         $peek = $this->_lexer->peek();
 - 
 -         while ($peek['value'] != $token) {
 -             $peek = $this->_lexer->peek();
 -         }
 - 
 -         $peek = $this->_lexer->peek();
 -         $this->_lexer->resetPeek();
 - 
 -         return $peek;
 -     }
 - 
 -     /**
 -      * Peek beyond the matched closing parenthesis and return the first token after that one.
 -      *
 -      * @return array
 -      */
 -     private function _peekBeyondClosingParenthesis()
 -     {
 -         $token = $this->_lexer->peek();
 -         $numUnmatched = 1;
 - 
 -         while ($numUnmatched > 0 && $token !== null) {
 -             if ($token['value'] == ')') {
 -                 --$numUnmatched;
 -             } else if ($token['value'] == '(') {
 -                 ++$numUnmatched;
 -             }
 - 
 -             $token = $this->_lexer->peek();
 -         }
 -         
 -         $this->_lexer->resetPeek();
 - 
 -         return $token;
 -     }
 - 
 -     /**
 -      * Checks if the given token indicates a mathematical operator.
 -      *
 -      * @return boolean TRUE if the token is a mathematical operator, FALSE otherwise.
 -      */
 -     private function _isMathOperator($token)
 -     {
 -         return in_array($token['value'], array("+", "-", "/", "*"));
 -     }
 - 
 -     /**
 -      * Checks if the next-next (after lookahead) token starts a function.
 -      *
 -      * @return boolean TRUE if the next-next tokens start a function, FALSE otherwise.
 -      */
 -     private function _isFunction()
 -     {
 -         $peek = $this->_lexer->peek();
 -         $nextpeek = $this->_lexer->peek();
 -         $this->_lexer->resetPeek();
 - 
 -         // We deny the COUNT(SELECT * FROM User u) here. COUNT won't be considered a function
 -         return ($peek['value'] === '(' && $nextpeek['type'] !== Lexer::T_SELECT);
 -     }
 - 
 -     /**
 -      * Checks whether the given token type indicates an aggregate function.
 -      *
 -      * @return boolean TRUE if the token type is an aggregate function, FALSE otherwise.
 -      */
 -     private function _isAggregateFunction($tokenType)
 -     {
 -         return $tokenType == Lexer::T_AVG || $tokenType == Lexer::T_MIN ||
 -                $tokenType == Lexer::T_MAX || $tokenType == Lexer::T_SUM ||
 -                $tokenType == Lexer::T_COUNT;
 -     }
 - 
 -     /**
 -      * Checks whether the current lookahead token of the lexer has the type
 -      * T_ALL, T_ANY or T_SOME.
 -      *
 -      * @return boolean
 -      */
 -     private function _isNextAllAnySome()
 -     {
 -         return $this->_lexer->lookahead['type'] === Lexer::T_ALL ||
 -                $this->_lexer->lookahead['type'] === Lexer::T_ANY ||
 -                $this->_lexer->lookahead['type'] === Lexer::T_SOME;
 -     }
 - 
 -     /**
 -      * Checks whether the next 2 tokens start a subselect.
 -      *
 -      * @return boolean TRUE if the next 2 tokens start a subselect, FALSE otherwise.
 -      */
 -     private function _isSubselect()
 -     {
 -         $la = $this->_lexer->lookahead;
 -         $next = $this->_lexer->glimpse();
 - 
 -         return ($la['value'] === '(' && $next['type'] === Lexer::T_SELECT);
 -     }
 - 
 -     /**
 -      * Validates that the given <tt>IdentificationVariable</tt> is semantically correct.
 -      * It must exist in query components list.
 -      *
 -      * @return void
 -      */
 -     private function _processDeferredIdentificationVariables()
 -     {
 -         foreach ($this->_deferredIdentificationVariables as $deferredItem) {
 -             $identVariable = $deferredItem['expression'];
 - 
 -             // Check if IdentificationVariable exists in queryComponents
 -             if ( ! isset($this->_queryComponents[$identVariable])) {
 -                 $this->semanticalError(
 -                     "'$identVariable' is not defined.", $deferredItem['token']
 -                 );
 -             }
 - 
 -             $qComp = $this->_queryComponents[$identVariable];
 - 
 -             // Check if queryComponent points to an AbstractSchemaName or a ResultVariable
 -             if ( ! isset($qComp['metadata'])) {
 -                 $this->semanticalError(
 -                     "'$identVariable' does not point to a Class.", $deferredItem['token']
 -                 );
 -             }
 - 
 -             // Validate if identification variable nesting level is lower or equal than the current one
 -             if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) {
 -                 $this->semanticalError(
 -                     "'$identVariable' is used outside the scope of its declaration.", $deferredItem['token']
 -                 );
 -             }
 -         }
 -     }
 - 
 -     /**
 -      * Validates that the given <tt>PartialObjectExpression</tt> is semantically correct.
 -      * It must exist in query components list.
 -      *
 -      * @return void
 -      */
 -     private function _processDeferredPartialObjectExpressions()
 -     {
 -         foreach ($this->_deferredPartialObjectExpressions as $deferredItem) {
 -             $expr = $deferredItem['expression'];
 -             $class = $this->_queryComponents[$expr->identificationVariable]['metadata'];
 - 
 -             foreach ($expr->partialFieldSet as $field) {
 -                 if ( ! isset($class->fieldMappings[$field])) {
 -                     $this->semanticalError(
 -                         "There is no mapped field named '$field' on class " . $class->name . ".",
 -                         $deferredItem['token']
 -                     );
 -                 }
 -             }
 - 
 -             if (array_intersect($class->identifier, $expr->partialFieldSet) != $class->identifier) {
 -                 $this->semanticalError(
 -                     "The partial field selection of class " . $class->name . " must contain the identifier.",
 -                     $deferredItem['token']
 -                 );
 -             }
 -         }
 -     }
 - 
 -     /**
 -      * Validates that the given <tt>ResultVariable</tt> is semantically correct.
 -      * It must exist in query components list.
 -      *
 -      * @return void
 -      */
 -     private function _processDeferredResultVariables()
 -     {
 -         foreach ($this->_deferredResultVariables as $deferredItem) {
 -             $resultVariable = $deferredItem['expression'];
 - 
 -             // Check if ResultVariable exists in queryComponents
 -             if ( ! isset($this->_queryComponents[$resultVariable])) {
 -                 $this->semanticalError(
 -                     "'$resultVariable' is not defined.", $deferredItem['token']
 -                 );
 -             }
 - 
 -             $qComp = $this->_queryComponents[$resultVariable];
 - 
 -             // Check if queryComponent points to an AbstractSchemaName or a ResultVariable
 -             if ( ! isset($qComp['resultVariable'])) {
 -                 $this->semanticalError(
 -                     "'$identVariable' does not point to a ResultVariable.", $deferredItem['token']
 -                 );
 -             }
 - 
 -             // Validate if identification variable nesting level is lower or equal than the current one
 -             if ($qComp['nestingLevel'] > $deferredItem['nestingLevel']) {
 -                 $this->semanticalError(
 -                     "'$resultVariable' is used outside the scope of its declaration.", $deferredItem['token']
 -                 );
 -             }
 -         }
 -     }
 - 
 -     /**
 -      * Validates that the given <tt>PathExpression</tt> is semantically correct for grammar rules:
 -      *
 -      * AssociationPathExpression             ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
 -      * SingleValuedPathExpression            ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
 -      * StateFieldPathExpression              ::= IdentificationVariable "." StateField
 -      * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
 -      * CollectionValuedPathExpression        ::= IdentificationVariable "." CollectionValuedAssociationField
 -      *
 -      * @param array $deferredItem
 -      * @param mixed $AST
 -      */
 -     private function _processDeferredPathExpressions($AST)
 -     {
 -         foreach ($this->_deferredPathExpressions as $deferredItem) {
 -             $pathExpression = $deferredItem['expression'];
 - 
 -             $qComp = $this->_queryComponents[$pathExpression->identificationVariable];
 -             $class = $qComp['metadata'];
 - 
 -             if (($field = $pathExpression->field) === null) {
 -                 $field = $pathExpression->field = $class->identifier[0];
 -             }
 -             
 -             // Check if field or association exists
 -             if ( ! isset($class->associationMappings[$field]) && ! isset($class->fieldMappings[$field])) {
 -                 $this->semanticalError(
 -                     'Class ' . $class->name . ' has no field or association named ' . $field,
 -                     $deferredItem['token']
 -                 );
 -             }
 - 
 -             if (isset($class->fieldMappings[$field])) {
 -                 $fieldType = AST\PathExpression::TYPE_STATE_FIELD;
 -             } else {
 -                 $assoc = $class->associationMappings[$field];
 -                 $class = $this->_em->getClassMetadata($assoc['targetEntity']);
 - 
 -                 if ($assoc['type'] & ClassMetadata::TO_ONE) {
 -                     $fieldType = AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION;
 -                 } else {
 -                     $fieldType = AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION;
 -                 }
 -             }
 - 
 -             // Validate if PathExpression is one of the expected types
 -             $expectedType = $pathExpression->expectedType;
 - 
 -             if ( ! ($expectedType & $fieldType)) {
 -                 // We need to recognize which was expected type(s)
 -                 $expectedStringTypes = array();
 - 
 -                 // Validate state field type
 -                 if ($expectedType & AST\PathExpression::TYPE_STATE_FIELD) {
 -                     $expectedStringTypes[] = 'StateFieldPathExpression';
 -                 }
 - 
 -                 // Validate single valued association (*-to-one)
 -                 if ($expectedType & AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION) {
 -                     $expectedStringTypes[] = 'SingleValuedAssociationField';
 -                 }
 - 
 -                 // Validate single valued association (*-to-many)
 -                 if ($expectedType & AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION) {
 -                     $expectedStringTypes[] = 'CollectionValuedAssociationField';
 -                 }
 - 
 -                 // Build the error message
 -                 $semanticalError = 'Invalid PathExpression. ';
 - 
 -                 if (count($expectedStringTypes) == 1) {
 -                     $semanticalError .= 'Must be a ' . $expectedStringTypes[0] . '.';
 -                 } else {
 -                     $semanticalError .= implode(' or ', $expectedStringTypes) . ' expected.';
 -                 }
 - 
 -                 $this->semanticalError($semanticalError, $deferredItem['token']);
 -             }
 -             
 -             // We need to force the type in PathExpression
 -             $pathExpression->type = $fieldType;
 -         }
 -     }
 - 
 -     /**
 -      * QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
 -      *
 -      * @return \Doctrine\ORM\Query\AST\SelectStatement |
 -      *         \Doctrine\ORM\Query\AST\UpdateStatement |
 -      *         \Doctrine\ORM\Query\AST\DeleteStatement
 -      */
 -     public function QueryLanguage()
 -     {
 -         $this->_lexer->moveNext();
 - 
 -         switch ($this->_lexer->lookahead['type']) {
 -             case Lexer::T_SELECT:
 -                 $statement = $this->SelectStatement();
 -                 break;
 -             case Lexer::T_UPDATE:
 -                 $statement = $this->UpdateStatement();
 -                 break;
 -             case Lexer::T_DELETE:
 -                 $statement = $this->DeleteStatement();
 -                 break;
 -             default:
 -                 $this->syntaxError('SELECT, UPDATE or DELETE');
 -                 break;
 -         }
 - 
 -         // Check for end of string
 -         if ($this->_lexer->lookahead !== null) {
 -             $this->syntaxError('end of string');
 -         }
 - 
 -         return $statement;
 -     }
 - 
 -     /**
 -      * SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
 -      *
 -      * @return \Doctrine\ORM\Query\AST\SelectStatement
 -      */
 -     public function SelectStatement()
 -     {
 -         $selectStatement = new AST\SelectStatement($this->SelectClause(), $this->FromClause());
 - 
 -         $selectStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE)
 -             ? $this->WhereClause() : null;
 - 
 -         $selectStatement->groupByClause = $this->_lexer->isNextToken(Lexer::T_GROUP)
 -             ? $this->GroupByClause() : null;
 - 
 -         $selectStatement->havingClause = $this->_lexer->isNextToken(Lexer::T_HAVING)
 -             ? $this->HavingClause() : null;
 - 
 -         $selectStatement->orderByClause = $this->_lexer->isNextToken(Lexer::T_ORDER)
 -             ? $this->OrderByClause() : null;
 - 
 -         return $selectStatement;
 -     }
 - 
 -     /**
 -      * UpdateStatement ::= UpdateClause [WhereClause]
 -      *
 -      * @return \Doctrine\ORM\Query\AST\UpdateStatement
 -      */
 -     public function UpdateStatement()
 -     {
 -         $updateStatement = new AST\UpdateStatement($this->UpdateClause());
 -         $updateStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE)
 -                 ? $this->WhereClause() : null;
 - 
 -         return $updateStatement;
 -     }
 - 
 -     /**
 -      * DeleteStatement ::= DeleteClause [WhereClause]
 -      *
 -      * @return \Doctrine\ORM\Query\AST\DeleteStatement
 -      */
 -     public function DeleteStatement()
 -     {
 -         $deleteStatement = new AST\DeleteStatement($this->DeleteClause());
 -         $deleteStatement->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE)
 -                 ? $this->WhereClause() : null;
 - 
 -         return $deleteStatement;
 -     }
 - 
 -     /**
 -      * IdentificationVariable ::= identifier
 -      *
 -      * @return string
 -      */
 -     public function IdentificationVariable()
 -     {
 -         $this->match(Lexer::T_IDENTIFIER);
 - 
 -         $identVariable = $this->_lexer->token['value'];
 - 
 -         $this->_deferredIdentificationVariables[] = array(
 -             'expression'   => $identVariable,
 -             'nestingLevel' => $this->_nestingLevel,
 -             'token'        => $this->_lexer->token,
 -         );
 - 
 -         return $identVariable;
 -     }
 - 
 -     /**
 -      * AliasIdentificationVariable = identifier
 -      *
 -      * @return string
 -      */
 -     public function AliasIdentificationVariable()
 -     {
 -         $this->match(Lexer::T_IDENTIFIER);
 - 
 -         $aliasIdentVariable = $this->_lexer->token['value'];
 -         $exists = isset($this->_queryComponents[$aliasIdentVariable]);
 - 
 -         if ($exists) {
 -             $this->semanticalError(
 -                 "'$aliasIdentVariable' is already defined.", $this->_lexer->token
 -             );
 -         }
 - 
 -         return $aliasIdentVariable;
 -     }
 - 
 -     /**
 -      * AbstractSchemaName ::= identifier
 -      *
 -      * @return string
 -      */
 -     public function AbstractSchemaName()
 -     {
 -         $this->match(Lexer::T_IDENTIFIER);
 - 
 -         $schemaName = ltrim($this->_lexer->token['value'], '\\');
 - 
 -         if (strrpos($schemaName, ':') !== false) {
 -             list($namespaceAlias, $simpleClassName) = explode(':', $schemaName);
 -             $schemaName = $this->_em->getConfiguration()->getEntityNamespace($namespaceAlias) . '\\' . $simpleClassName;
 -         }
 - 
 -         $exists = class_exists($schemaName, true);
 - 
 -         if ( ! $exists) {
 -             $this->semanticalError("Class '$schemaName' is not defined.", $this->_lexer->token);
 -         }
 - 
 -         return $schemaName;
 -     }
 - 
 -     /**
 -      * AliasResultVariable ::= identifier
 -      *
 -      * @return string
 -      */
 -     public function AliasResultVariable()
 -     {
 -         $this->match(Lexer::T_IDENTIFIER);
 - 
 -         $resultVariable = $this->_lexer->token['value'];
 -         $exists = isset($this->_queryComponents[$resultVariable]);
 - 
 -         if ($exists) {
 -             $this->semanticalError(
 -                 "'$resultVariable' is already defined.", $this->_lexer->token
 -             );
 -         }
 - 
 -         return $resultVariable;
 -     }
 - 
 -     /**
 -      * ResultVariable ::= identifier
 -      *
 -      * @return string
 -      */
 -     public function ResultVariable()
 -     {
 -         $this->match(Lexer::T_IDENTIFIER);
 - 
 -         $resultVariable = $this->_lexer->token['value'];
 - 
 -         // Defer ResultVariable validation
 -         $this->_deferredResultVariables[] = array(
 -             'expression'   => $resultVariable,
 -             'nestingLevel' => $this->_nestingLevel,
 -             'token'        => $this->_lexer->token,
 -         );
 - 
 -         return $resultVariable;
 -     }
 - 
 -     /**
 -      * JoinAssociationPathExpression ::= IdentificationVariable "." (CollectionValuedAssociationField | SingleValuedAssociationField)
 -      *
 -      * @return \Doctrine\ORM\Query\AST\JoinAssociationPathExpression
 -      */
 -     public function JoinAssociationPathExpression()
 -     {
 -         $token = $this->_lexer->lookahead;
 -         $identVariable = $this->IdentificationVariable();
 - 
 -         if (!isset($this->_queryComponents[$identVariable])) {
 -             $this->semanticalError('Identification Variable ' . $identVariable .' used in join path expression but was not defined before.');
 -         }
 - 
 -         $this->match(Lexer::T_DOT);
 -         $this->match(Lexer::T_IDENTIFIER);
 - 
 -         $field = $this->_lexer->token['value'];
 - 
 -         // Validate association field
 -         $qComp = $this->_queryComponents[$identVariable];
 -         $class = $qComp['metadata'];
 - 
 -         if ( ! isset($class->associationMappings[$field])) {
 -             $this->semanticalError('Class ' . $class->name . ' has no association named ' . $field);
 -         }
 - 
 -         return new AST\JoinAssociationPathExpression($identVariable, $field);
 -     }
 - 
 -     /**
 -      * Parses an arbitrary path expression and defers semantical validation
 -      * based on expected types.
 -      *
 -      * PathExpression ::= IdentificationVariable "." identifier
 -      *
 -      * @param integer $expectedTypes
 -      * @return \Doctrine\ORM\Query\AST\PathExpression
 -      */
 -     public function PathExpression($expectedTypes)
 -     {
 -         $token = $this->_lexer->lookahead;
 -         $identVariable = $this->IdentificationVariable();
 -         $field = null;
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_DOT)) {
 -             $this->match(Lexer::T_DOT);
 -             $this->match(Lexer::T_IDENTIFIER);
 - 
 -             $field = $this->_lexer->token['value'];
 -         }
 -         
 -         // Creating AST node
 -         $pathExpr = new AST\PathExpression($expectedTypes, $identVariable, $field);
 - 
 -         // Defer PathExpression validation if requested to be defered
 -         $this->_deferredPathExpressions[] = array(
 -             'expression'   => $pathExpr,
 -             'nestingLevel' => $this->_nestingLevel,
 -             'token'        => $this->_lexer->token,
 -         );
 - 
 -         return $pathExpr;
 -     }
 - 
 -     /**
 -      * AssociationPathExpression ::= CollectionValuedPathExpression | SingleValuedAssociationPathExpression
 -      *
 -      * @return \Doctrine\ORM\Query\AST\PathExpression
 -      */
 -     public function AssociationPathExpression()
 -     {
 -         return $this->PathExpression(
 -             AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION |
 -             AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION
 -         );
 -     }
 - 
 -     /**
 -      * SingleValuedPathExpression ::= StateFieldPathExpression | SingleValuedAssociationPathExpression
 -      *
 -      * @return \Doctrine\ORM\Query\AST\PathExpression
 -      */
 -     public function SingleValuedPathExpression()
 -     {
 -         return $this->PathExpression(
 -             AST\PathExpression::TYPE_STATE_FIELD |
 -             AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION
 -         );
 -     }
 - 
 -     /**
 -      * StateFieldPathExpression ::= IdentificationVariable "." StateField
 -      *
 -      * @return \Doctrine\ORM\Query\AST\PathExpression
 -      */
 -     public function StateFieldPathExpression()
 -     {
 -         return $this->PathExpression(AST\PathExpression::TYPE_STATE_FIELD);
 -     }
 - 
 -     /**
 -      * SingleValuedAssociationPathExpression ::= IdentificationVariable "." SingleValuedAssociationField
 -      *
 -      * @return \Doctrine\ORM\Query\AST\PathExpression
 -      */
 -     public function SingleValuedAssociationPathExpression()
 -     {
 -         return $this->PathExpression(AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION);
 -     }
 - 
 -     /**
 -      * CollectionValuedPathExpression ::= IdentificationVariable "." CollectionValuedAssociationField
 -      *
 -      * @return \Doctrine\ORM\Query\AST\PathExpression
 -      */
 -     public function CollectionValuedPathExpression()
 -     {
 -         return $this->PathExpression(AST\PathExpression::TYPE_COLLECTION_VALUED_ASSOCIATION);
 -     }
 - 
 -     /**
 -      * SelectClause ::= "SELECT" ["DISTINCT"] SelectExpression {"," SelectExpression}
 -      *
 -      * @return \Doctrine\ORM\Query\AST\SelectClause
 -      */
 -     public function SelectClause()
 -     {
 -         $isDistinct = false;
 -         $this->match(Lexer::T_SELECT);
 - 
 -         // Check for DISTINCT
 -         if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
 -             $this->match(Lexer::T_DISTINCT);
 -             $isDistinct = true;
 -         }
 - 
 -         // Process SelectExpressions (1..N)
 -         $selectExpressions = array();
 -         $selectExpressions[] = $this->SelectExpression();
 - 
 -         while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
 -             $this->match(Lexer::T_COMMA);
 -             $selectExpressions[] = $this->SelectExpression();
 -         }
 - 
 -         return new AST\SelectClause($selectExpressions, $isDistinct);
 -     }
 - 
 -     /**
 -      * SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression
 -      *
 -      * @return \Doctrine\ORM\Query\AST\SimpleSelectClause
 -      */
 -     public function SimpleSelectClause()
 -     {
 -         $isDistinct = false;
 -         $this->match(Lexer::T_SELECT);
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
 -             $this->match(Lexer::T_DISTINCT);
 -             $isDistinct = true;
 -         }
 - 
 -         return new AST\SimpleSelectClause($this->SimpleSelectExpression(), $isDistinct);
 -     }
 - 
 -     /**
 -      * UpdateClause ::= "UPDATE" AbstractSchemaName ["AS"] AliasIdentificationVariable "SET" UpdateItem {"," UpdateItem}*
 -      *
 -      * @return \Doctrine\ORM\Query\AST\UpdateClause
 -      */
 -     public function UpdateClause()
 -     {
 -         $this->match(Lexer::T_UPDATE);
 -         $token = $this->_lexer->lookahead;
 -         $abstractSchemaName = $this->AbstractSchemaName();
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_AS)) {
 -             $this->match(Lexer::T_AS);
 -         }
 - 
 -         $aliasIdentificationVariable = $this->AliasIdentificationVariable();
 - 
 -         $class = $this->_em->getClassMetadata($abstractSchemaName);
 - 
 -         // Building queryComponent
 -         $queryComponent = array(
 -             'metadata'     => $class,
 -             'parent'       => null,
 -             'relation'     => null,
 -             'map'          => null,
 -             'nestingLevel' => $this->_nestingLevel,
 -             'token'        => $token,
 -         );
 -         $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
 - 
 -         $this->match(Lexer::T_SET);
 - 
 -         $updateItems = array();
 -         $updateItems[] = $this->UpdateItem();
 - 
 -         while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
 -             $this->match(Lexer::T_COMMA);
 -             $updateItems[] = $this->UpdateItem();
 -         }
 - 
 -         $updateClause = new AST\UpdateClause($abstractSchemaName, $updateItems);
 -         $updateClause->aliasIdentificationVariable = $aliasIdentificationVariable;
 - 
 -         return $updateClause;
 -     }
 - 
 -     /**
 -      * DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName ["AS"] AliasIdentificationVariable
 -      *
 -      * @return \Doctrine\ORM\Query\AST\DeleteClause
 -      */
 -     public function DeleteClause()
 -     {
 -         $this->match(Lexer::T_DELETE);
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_FROM)) {
 -             $this->match(Lexer::T_FROM);
 -         }
 - 
 -         $token = $this->_lexer->lookahead;
 -         $deleteClause = new AST\DeleteClause($this->AbstractSchemaName());
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_AS)) {
 -             $this->match(Lexer::T_AS);
 -         }
 - 
 -         $aliasIdentificationVariable = $this->AliasIdentificationVariable();
 - 
 -         $deleteClause->aliasIdentificationVariable = $aliasIdentificationVariable;
 -         $class = $this->_em->getClassMetadata($deleteClause->abstractSchemaName);
 - 
 -         // Building queryComponent
 -         $queryComponent = array(
 -             'metadata'     => $class,
 -             'parent'       => null,
 -             'relation'     => null,
 -             'map'          => null,
 -             'nestingLevel' => $this->_nestingLevel,
 -             'token'        => $token,
 -         );
 -         $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
 - 
 -         return $deleteClause;
 -     }
 - 
 -     /**
 -      * FromClause ::= "FROM" IdentificationVariableDeclaration {"," IdentificationVariableDeclaration}*
 -      *
 -      * @return \Doctrine\ORM\Query\AST\FromClause
 -      */
 -     public function FromClause()
 -     {
 -         $this->match(Lexer::T_FROM);
 -         $identificationVariableDeclarations = array();
 -         $identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration();
 - 
 -         while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
 -             $this->match(Lexer::T_COMMA);
 -             $identificationVariableDeclarations[] = $this->IdentificationVariableDeclaration();
 -         }
 - 
 -         return new AST\FromClause($identificationVariableDeclarations);
 -     }
 - 
 -     /**
 -      * SubselectFromClause ::= "FROM" SubselectIdentificationVariableDeclaration {"," SubselectIdentificationVariableDeclaration}*
 -      *
 -      * @return \Doctrine\ORM\Query\AST\SubselectFromClause
 -      */
 -     public function SubselectFromClause()
 -     {
 -         $this->match(Lexer::T_FROM);
 -         $identificationVariables = array();
 -         $identificationVariables[] = $this->SubselectIdentificationVariableDeclaration();
 - 
 -         while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
 -             $this->match(Lexer::T_COMMA);
 -             $identificationVariables[] = $this->SubselectIdentificationVariableDeclaration();
 -         }
 - 
 -         return new AST\SubselectFromClause($identificationVariables);
 -     }
 - 
 -     /**
 -      * WhereClause ::= "WHERE" ConditionalExpression
 -      *
 -      * @return \Doctrine\ORM\Query\AST\WhereClause
 -      */
 -     public function WhereClause()
 -     {
 -         $this->match(Lexer::T_WHERE);
 - 
 -         return new AST\WhereClause($this->ConditionalExpression());
 -     }
 - 
 -     /**
 -      * HavingClause ::= "HAVING" ConditionalExpression
 -      *
 -      * @return \Doctrine\ORM\Query\AST\HavingClause
 -      */
 -     public function HavingClause()
 -     {
 -         $this->match(Lexer::T_HAVING);
 - 
 -         return new AST\HavingClause($this->ConditionalExpression());
 -     }
 - 
 -     /**
 -      * GroupByClause ::= "GROUP" "BY" GroupByItem {"," GroupByItem}*
 -      *
 -      * @return \Doctrine\ORM\Query\AST\GroupByClause
 -      */
 -     public function GroupByClause()
 -     {
 -         $this->match(Lexer::T_GROUP);
 -         $this->match(Lexer::T_BY);
 - 
 -         $groupByItems = array($this->GroupByItem());
 - 
 -         while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
 -             $this->match(Lexer::T_COMMA);
 -             $groupByItems[] = $this->GroupByItem();
 -         }
 - 
 -         return new AST\GroupByClause($groupByItems);
 -     }
 - 
 -     /**
 -      * OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*
 -      *
 -      * @return \Doctrine\ORM\Query\AST\OrderByClause
 -      */
 -     public function OrderByClause()
 -     {
 -         $this->match(Lexer::T_ORDER);
 -         $this->match(Lexer::T_BY);
 - 
 -         $orderByItems = array();
 -         $orderByItems[] = $this->OrderByItem();
 - 
 -         while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
 -             $this->match(Lexer::T_COMMA);
 -             $orderByItems[] = $this->OrderByItem();
 -         }
 - 
 -         return new AST\OrderByClause($orderByItems);
 -     }
 - 
 -     /**
 -      * Subselect ::= SimpleSelectClause SubselectFromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
 -      *
 -      * @return \Doctrine\ORM\Query\AST\Subselect
 -      */
 -     public function Subselect()
 -     {
 -         // Increase query nesting level
 -         $this->_nestingLevel++;
 - 
 -         $subselect = new AST\Subselect($this->SimpleSelectClause(), $this->SubselectFromClause());
 - 
 -         $subselect->whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE)
 -             ? $this->WhereClause() : null;
 - 
 -         $subselect->groupByClause = $this->_lexer->isNextToken(Lexer::T_GROUP)
 -             ? $this->GroupByClause() : null;
 - 
 -         $subselect->havingClause = $this->_lexer->isNextToken(Lexer::T_HAVING)
 -             ? $this->HavingClause() : null;
 - 
 -         $subselect->orderByClause = $this->_lexer->isNextToken(Lexer::T_ORDER)
 -             ? $this->OrderByClause() : null;
 - 
 -         // Decrease query nesting level
 -         $this->_nestingLevel--;
 - 
 -         return $subselect;
 -     }
 - 
 -     /**
 -      * UpdateItem ::= SingleValuedPathExpression "=" NewValue
 -      *
 -      * @return \Doctrine\ORM\Query\AST\UpdateItem
 -      */
 -     public function UpdateItem()
 -     {
 -         $pathExpr = $this->SingleValuedPathExpression();
 - 
 -         $this->match(Lexer::T_EQUALS);
 - 
 -         $updateItem = new AST\UpdateItem($pathExpr, $this->NewValue());
 - 
 -         return $updateItem;
 -     }
 - 
 -     /**
 -      * GroupByItem ::= IdentificationVariable | SingleValuedPathExpression
 -      *
 -      * @return string | \Doctrine\ORM\Query\AST\PathExpression
 -      */
 -     public function GroupByItem()
 -     {
 -         // We need to check if we are in a IdentificationVariable or SingleValuedPathExpression
 -         $glimpse = $this->_lexer->glimpse();
 - 
 -         if ($glimpse['type'] != Lexer::T_DOT) {
 -             $token = $this->_lexer->lookahead;
 -             $identVariable = $this->IdentificationVariable();
 - 
 -             if (!isset($this->_queryComponents[$identVariable])) {
 -                 $this->semanticalError('Cannot group by undefined identification variable.');
 -             }
 - 
 -             return $identVariable;
 -         }
 - 
 -         return $this->SingleValuedPathExpression();
 -     }
 - 
 -     /**
 -      * OrderByItem ::= (ResultVariable | StateFieldPathExpression) ["ASC" | "DESC"]
 -      *
 -      * @todo Post 2.0 release. Support general SingleValuedPathExpression instead
 -      * of only StateFieldPathExpression.
 -      *
 -      * @return \Doctrine\ORM\Query\AST\OrderByItem
 -      */
 -     public function OrderByItem()
 -     {
 -         $type = 'ASC';
 - 
 -         // We need to check if we are in a ResultVariable or StateFieldPathExpression
 -         $glimpse = $this->_lexer->glimpse();
 - 
 -         if ($glimpse['type'] != Lexer::T_DOT) {
 -             $token = $this->_lexer->lookahead;
 -             $expr = $this->ResultVariable();
 -         } else {
 -             $expr = $this->StateFieldPathExpression();
 -         }
 - 
 -         $item = new AST\OrderByItem($expr);
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_ASC)) {
 -             $this->match(Lexer::T_ASC);
 -         } else if ($this->_lexer->isNextToken(Lexer::T_DESC)) {
 -             $this->match(Lexer::T_DESC);
 -             $type = 'DESC';
 -         }
 - 
 -         $item->type = $type;
 -         return $item;
 -     }
 - 
 -     /**
 -      * NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary |
 -      *      EnumPrimary | SimpleEntityExpression | "NULL"
 -      *
 -      * NOTE: Since it is not possible to correctly recognize individual types, here is the full
 -      * grammar that needs to be supported:
 -      *
 -      * NewValue ::= SimpleArithmeticExpression | "NULL"
 -      *
 -      * SimpleArithmeticExpression covers all *Primary grammar rules and also SimplEntityExpression
 -      */
 -     public function NewValue()
 -     {
 -         if ($this->_lexer->isNextToken(Lexer::T_NULL)) {
 -             $this->match(Lexer::T_NULL);
 -             return null;
 -         } else if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
 -             $this->match(Lexer::T_INPUT_PARAMETER);
 -             return new AST\InputParameter($this->_lexer->token['value']);
 -         }
 - 
 -         return $this->SimpleArithmeticExpression();
 -     }
 - 
 -     /**
 -      * IdentificationVariableDeclaration ::= RangeVariableDeclaration [IndexBy] {JoinVariableDeclaration}*
 -      *
 -      * @return \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration
 -      */
 -     public function IdentificationVariableDeclaration()
 -     {
 -         $rangeVariableDeclaration = $this->RangeVariableDeclaration();
 -         $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX) ? $this->IndexBy() : null;
 -         $joinVariableDeclarations = array();
 - 
 -         while (
 -             $this->_lexer->isNextToken(Lexer::T_LEFT) ||
 -             $this->_lexer->isNextToken(Lexer::T_INNER) ||
 -             $this->_lexer->isNextToken(Lexer::T_JOIN)
 -         ) {
 -             $joinVariableDeclarations[] = $this->JoinVariableDeclaration();
 -         }
 - 
 -         return new AST\IdentificationVariableDeclaration(
 -             $rangeVariableDeclaration, $indexBy, $joinVariableDeclarations
 -         );
 -     }
 - 
 -     /**
 -      * SubselectIdentificationVariableDeclaration ::= IdentificationVariableDeclaration | (AssociationPathExpression ["AS"] AliasIdentificationVariable)
 -      *
 -      * @return \Doctrine\ORM\Query\AST\SubselectIdentificationVariableDeclaration |
 -      *         \Doctrine\ORM\Query\AST\IdentificationVariableDeclaration
 -      */
 -     public function SubselectIdentificationVariableDeclaration()
 -     {
 -         $glimpse = $this->_lexer->glimpse();
 - 
 -         /* NOT YET IMPLEMENTED!
 - 
 -         if ($glimpse['type'] == Lexer::T_DOT) {
 -             $subselectIdVarDecl = new AST\SubselectIdentificationVariableDeclaration();
 -             $subselectIdVarDecl->associationPathExpression = $this->AssociationPathExpression();
 -             $this->match(Lexer::T_AS);
 -             $subselectIdVarDecl->aliasIdentificationVariable = $this->AliasIdentificationVariable();
 - 
 -             return $subselectIdVarDecl;
 -         }
 -         */
 - 
 -         return $this->IdentificationVariableDeclaration();
 -     }
 - 
 -     /**
 -      * JoinVariableDeclaration ::= Join [IndexBy]
 -      *
 -      * @return \Doctrine\ORM\Query\AST\JoinVariableDeclaration
 -      */
 -     public function JoinVariableDeclaration()
 -     {
 -         $join = $this->Join();
 -         $indexBy = $this->_lexer->isNextToken(Lexer::T_INDEX)
 -                 ? $this->IndexBy() : null;
 - 
 -         return new AST\JoinVariableDeclaration($join, $indexBy);
 -     }
 - 
 -     /**
 -      * RangeVariableDeclaration ::= AbstractSchemaName ["AS"] AliasIdentificationVariable
 -      *
 -      * @return \Doctrine\ORM\Query\AST\RangeVariableDeclaration
 -      */
 -     public function RangeVariableDeclaration()
 -     {
 -         $abstractSchemaName = $this->AbstractSchemaName();
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_AS)) {
 -             $this->match(Lexer::T_AS);
 -         }
 - 
 -         $token = $this->_lexer->lookahead;
 -         $aliasIdentificationVariable = $this->AliasIdentificationVariable();
 -         $classMetadata = $this->_em->getClassMetadata($abstractSchemaName);
 - 
 -         // Building queryComponent
 -         $queryComponent = array(
 -             'metadata'     => $classMetadata,
 -             'parent'       => null,
 -             'relation'     => null,
 -             'map'          => null,
 -             'nestingLevel' => $this->_nestingLevel,
 -             'token'        => $token
 -         );
 -         $this->_queryComponents[$aliasIdentificationVariable] = $queryComponent;
 - 
 -         return new AST\RangeVariableDeclaration($abstractSchemaName, $aliasIdentificationVariable);
 -     }
 - 
 -     /**
 -      * PartialObjectExpression ::= "PARTIAL" IdentificationVariable "." PartialFieldSet
 -      * PartialFieldSet ::= "{" SimpleStateField {"," SimpleStateField}* "}"
 -      *
 -      * @return array
 -      */
 -     public function PartialObjectExpression()
 -     {
 -         $this->match(Lexer::T_PARTIAL);
 - 
 -         $partialFieldSet = array();
 - 
 -         $identificationVariable = $this->IdentificationVariable();
 -         $this->match(Lexer::T_DOT);
 - 
 -         $this->match(Lexer::T_OPEN_CURLY_BRACE);
 -         $this->match(Lexer::T_IDENTIFIER);
 -         $partialFieldSet[] = $this->_lexer->token['value'];
 - 
 -         while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
 -             $this->match(Lexer::T_COMMA);
 -             $this->match(Lexer::T_IDENTIFIER);
 -             $partialFieldSet[] = $this->_lexer->token['value'];
 -         }
 -         
 -         $this->match(Lexer::T_CLOSE_CURLY_BRACE);
 - 
 -         $partialObjectExpression = new AST\PartialObjectExpression($identificationVariable, $partialFieldSet);
 - 
 -         // Defer PartialObjectExpression validation
 -         $this->_deferredPartialObjectExpressions[] = array(
 -             'expression'   => $partialObjectExpression,
 -             'nestingLevel' => $this->_nestingLevel,
 -             'token'        => $this->_lexer->token,
 -         );
 - 
 -         return $partialObjectExpression;
 -     }
 - 
 -     /**
 -      * Join ::= ["LEFT" ["OUTER"] | "INNER"] "JOIN" JoinAssociationPathExpression
 -      *          ["AS"] AliasIdentificationVariable ["WITH" ConditionalExpression]
 -      *
 -      * @return \Doctrine\ORM\Query\AST\Join
 -      */
 -     public function Join()
 -     {
 -         // Check Join type
 -         $joinType = AST\Join::JOIN_TYPE_INNER;
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_LEFT)) {
 -             $this->match(Lexer::T_LEFT);
 - 
 -             // Possible LEFT OUTER join
 -             if ($this->_lexer->isNextToken(Lexer::T_OUTER)) {
 -                 $this->match(Lexer::T_OUTER);
 -                 $joinType = AST\Join::JOIN_TYPE_LEFTOUTER;
 -             } else {
 -                 $joinType = AST\Join::JOIN_TYPE_LEFT;
 -             }
 -         } else if ($this->_lexer->isNextToken(Lexer::T_INNER)) {
 -             $this->match(Lexer::T_INNER);
 -         }
 - 
 -         $this->match(Lexer::T_JOIN);
 - 
 -         $joinPathExpression = $this->JoinAssociationPathExpression();
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_AS)) {
 -             $this->match(Lexer::T_AS);
 -         }
 - 
 -         $token = $this->_lexer->lookahead;
 -         $aliasIdentificationVariable = $this->AliasIdentificationVariable();
 - 
 -         // Verify that the association exists.
 -         $parentClass = $this->_queryComponents[$joinPathExpression->identificationVariable]['metadata'];
 -         $assocField = $joinPathExpression->associationField;
 - 
 -         if ( ! $parentClass->hasAssociation($assocField)) {
 -             $this->semanticalError(
 -                 "Class " . $parentClass->name . " has no association named '$assocField'."
 -             );
 -         }
 - 
 -         $targetClassName = $parentClass->associationMappings[$assocField]['targetEntity'];
 - 
 -         // Building queryComponent
 -         $joinQueryComponent = array(
 -             'metadata'     => $this->_em->getClassMetadata($targetClassName),
 -             'parent'       => $joinPathExpression->identificationVariable,
 -             'relation'     => $parentClass->getAssociationMapping($assocField),
 -             'map'          => null,
 -             'nestingLevel' => $this->_nestingLevel,
 -             'token'        => $token
 -         );
 -         $this->_queryComponents[$aliasIdentificationVariable] = $joinQueryComponent;
 - 
 -         // Create AST node
 -         $join = new AST\Join($joinType, $joinPathExpression, $aliasIdentificationVariable);
 - 
 -         // Check for ad-hoc Join conditions
 -         if ($this->_lexer->isNextToken(Lexer::T_WITH)) {
 -             $this->match(Lexer::T_WITH);
 -             $join->conditionalExpression = $this->ConditionalExpression();
 -         }
 - 
 -         return $join;
 -     }
 - 
 -     /**
 -      * IndexBy ::= "INDEX" "BY" StateFieldPathExpression
 -      *
 -      * @return \Doctrine\ORM\Query\AST\IndexBy
 -      */
 -     public function IndexBy()
 -     {
 -         $this->match(Lexer::T_INDEX);
 -         $this->match(Lexer::T_BY);
 -         $pathExpr = $this->StateFieldPathExpression();
 - 
 -         // Add the INDEX BY info to the query component
 -         $this->_queryComponents[$pathExpr->identificationVariable]['map'] = $pathExpr->field;
 - 
 -         return new AST\IndexBy($pathExpr);
 -     }
 - 
 -     /**
 -      * ScalarExpression ::= SimpleArithmeticExpression | StringPrimary | DateTimePrimary |
 -      *                      StateFieldPathExpression | BooleanPrimary | CaseExpression |
 -      *                      EntityTypeExpression
 -      *
 -      * @return mixed One of the possible expressions or subexpressions.
 -      */
 -     public function ScalarExpression()
 -     {
 -         $lookahead = $this->_lexer->lookahead['type'];
 -         if ($lookahead === Lexer::T_IDENTIFIER) {
 -             $this->_lexer->peek(); // lookahead => '.'
 -             $this->_lexer->peek(); // lookahead => token after '.'
 -             $peek = $this->_lexer->peek(); // lookahead => token after the token after the '.'
 -             $this->_lexer->resetPeek();
 - 
 -             if ($this->_isMathOperator($peek)) {
 -                 return $this->SimpleArithmeticExpression();
 -             }
 - 
 -             return $this->StateFieldPathExpression();
 -         } else if ($lookahead == Lexer::T_INTEGER || $lookahead == Lexer::T_FLOAT) {
 -             return $this->SimpleArithmeticExpression();
 -         } else if ($lookahead == Lexer::T_CASE || $lookahead == Lexer::T_COALESCE || $lookahead == Lexer::T_NULLIF) {
 -             // Since NULLIF and COALESCE can be identified as a function, 
 -             // we need to check if before check for FunctionDeclaration
 -             return $this->CaseExpression();
 -         } else if ($this->_isFunction() || $this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
 -             // We may be in an ArithmeticExpression (find the matching ")" and inspect for Math operator)
 -             $this->_lexer->peek(); // "("
 -             $peek = $this->_peekBeyondClosingParenthesis();
 - 
 -             if ($this->_isMathOperator($peek)) {
 -                 return $this->SimpleArithmeticExpression();
 -             }
 - 
 -             if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
 -                 return $this->AggregateExpression();
 -             } else {
 -                 return $this->FunctionDeclaration();
 -             }
 -         } else if ($lookahead == Lexer::T_STRING) {
 -             return $this->StringPrimary();
 -         } else if ($lookahead == Lexer::T_INPUT_PARAMETER) {
 -             return $this->InputParameter();
 -         } else if ($lookahead == Lexer::T_TRUE || $lookahead == Lexer::T_FALSE) {
 -             $this->match($lookahead);
 -             return new AST\Literal(AST\Literal::BOOLEAN, $this->_lexer->token['value']);
 -         } else {
 -             $this->syntaxError();
 -         }
 -     }
 - 
 -     public function CaseExpression()
 -     {
 -         $lookahead = $this->_lexer->lookahead['type'];
 -         
 -         // if "CASE" "WHEN" => GeneralCaseExpression
 -         // else if "CASE" => SimpleCaseExpression
 -         // [DONE] else if "COALESCE" => CoalesceExpression
 -         // [DONE] else if "NULLIF" => NullifExpression
 -         switch ($lookahead) {
 -             case Lexer::T_NULLIF:
 -                 return $this->NullIfExpression();
 -                 
 -             case Lexer::T_COALESCE:
 -                 return $this->CoalesceExpression();
 -                 
 -             default:
 -                 $this->semanticalError('CaseExpression not yet supported.');
 -                 return null;
 -         }
 -     }
 -     
 -     /**
 -      * CoalesceExpression ::= "COALESCE" "(" ScalarExpression {"," ScalarExpression}* ")"
 -      * 
 -      * @return \Doctrine\ORM\Query\AST\CoalesceExpression
 -      */
 -     public function CoalesceExpression()
 -     {
 -         $this->match(Lexer::T_COALESCE);
 -         $this->match(Lexer::T_OPEN_PARENTHESIS);
 -         
 -         // Process ScalarExpressions (1..N)
 -         $scalarExpressions = array();
 -         $scalarExpressions[] = $this->ScalarExpression();
 - 
 -         while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
 -             $this->match(Lexer::T_COMMA);
 -             $scalarExpressions[] = $this->ScalarExpression();
 -         }
 -         
 -         $this->match(Lexer::T_CLOSE_PARENTHESIS);
 -         
 -         return new AST\CoalesceExpression($scalarExpressions);
 -     }
 -     
 -     /**
 -      * NullIfExpression ::= "NULLIF" "(" ScalarExpression "," ScalarExpression ")"
 -      * 
 -      * @return \Doctrine\ORM\Query\AST\ExistsExpression
 -      */
 -     public function NullIfExpression()
 -     {
 -         $this->match(Lexer::T_NULLIF);
 -         $this->match(Lexer::T_OPEN_PARENTHESIS);
 -         
 -         $firstExpression = $this->ScalarExpression();
 -         $this->match(Lexer::T_COMMA);
 -         $secondExpression = $this->ScalarExpression();
 -         
 -         $this->match(Lexer::T_CLOSE_PARENTHESIS);
 - 
 -         return new AST\NullIfExpression($firstExpression, $secondExpression);
 -     }
 - 
 -     /**
 -      * SelectExpression ::=
 -      *      IdentificationVariable | StateFieldPathExpression |
 -      *      (AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable]
 -      *
 -      * @return \Doctrine\ORM\Query\AST\SelectExpression
 -      */
 -     public function SelectExpression()
 -     {
 -         $expression = null;
 -         $identVariable = null;
 -         $fieldAliasIdentificationVariable = null;
 -         $peek = $this->_lexer->glimpse();
 - 
 -         $supportsAlias = true;
 - 
 -         if ($peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) {
 -             if ($peek['value'] == '.') {
 -                 // ScalarExpression
 -                 $expression = $this->ScalarExpression();
 -             } else {
 -                 $supportsAlias = false;
 -                 $expression = $identVariable = $this->IdentificationVariable();
 -             }
 -         } else if ($this->_lexer->lookahead['value'] == '(') {
 -             if ($peek['type'] == Lexer::T_SELECT) {
 -                 // Subselect
 -                 $this->match(Lexer::T_OPEN_PARENTHESIS);
 -                 $expression = $this->Subselect();
 -                 $this->match(Lexer::T_CLOSE_PARENTHESIS);
 -             } else {
 -                 // Shortcut: ScalarExpression => SimpleArithmeticExpression
 -                 $expression = $this->SimpleArithmeticExpression();
 -             }
 -         } else if ($this->_isFunction()) {
 -             $this->_lexer->peek(); // "("
 -             
 -             $lookaheadType = $this->_lexer->lookahead['type'];
 -             $beyond        = $this->_peekBeyondClosingParenthesis();
 -             
 -             if ($this->_isMathOperator($beyond)) {
 -                 $expression = $this->ScalarExpression();
 -             } else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
 -                 $expression = $this->AggregateExpression();
 -             } else if (in_array ($lookaheadType, array(Lexer::T_CASE, Lexer::T_COALESCE, Lexer::T_NULLIF))) {
 -                 $expression = $this->CaseExpression();
 -             } else {
 -                 // Shortcut: ScalarExpression => Function
 -                 $expression = $this->FunctionDeclaration();
 -             }
 -         } else if ($this->_lexer->lookahead['type'] == Lexer::T_PARTIAL) {
 -             $supportsAlias = false;
 -             $expression = $this->PartialObjectExpression();
 -             $identVariable = $expression->identificationVariable;
 -         } else if ($this->_lexer->lookahead['type'] == Lexer::T_INTEGER ||
 -                 $this->_lexer->lookahead['type'] == Lexer::T_FLOAT ||
 -                 $this->_lexer->lookahead['type'] == Lexer::T_STRING) {
 -             // Shortcut: ScalarExpression => SimpleArithmeticExpression
 -             $expression = $this->SimpleArithmeticExpression();
 -         } else {
 -             $this->syntaxError('IdentificationVariable | StateFieldPathExpression'
 -                     . ' | AggregateExpression | "(" Subselect ")" | ScalarExpression',
 -                     $this->_lexer->lookahead);
 -         }
 - 
 -         if ($supportsAlias) {
 -             if ($this->_lexer->isNextToken(Lexer::T_AS)) {
 -                 $this->match(Lexer::T_AS);
 -             }
 - 
 -             if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
 -                 $token = $this->_lexer->lookahead;
 -                 $fieldAliasIdentificationVariable = $this->AliasResultVariable();
 - 
 -                 // Include AliasResultVariable in query components.
 -                 $this->_queryComponents[$fieldAliasIdentificationVariable] = array(
 -                     'resultVariable' => $expression,
 -                     'nestingLevel'   => $this->_nestingLevel,
 -                     'token'          => $token,
 -                 );
 -             }
 -         }
 - 
 -         $expr = new AST\SelectExpression($expression, $fieldAliasIdentificationVariable);
 -         if (!$supportsAlias) {
 -             $this->_identVariableExpressions[$identVariable] = $expr;
 -         }
 -         return $expr;
 -     }
 - 
 -     /**
 -      * SimpleSelectExpression ::=
 -      *      StateFieldPathExpression | IdentificationVariable |
 -      *      ((AggregateExpression | "(" Subselect ")" | ScalarExpression) [["AS"] AliasResultVariable])
 -      *
 -      * @return \Doctrine\ORM\Query\AST\SimpleSelectExpression
 -      */
 -     public function SimpleSelectExpression()
 -     {
 -         $peek = $this->_lexer->glimpse();
 - 
 -         if ($peek['value'] != '(' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) {
 -             // SingleValuedPathExpression | IdentificationVariable
 -             if ($peek['value'] == '.') {
 -                 $expression = $this->StateFieldPathExpression();
 -             } else {
 -                 $expression = $this->IdentificationVariable();
 -             }
 - 
 -             return new AST\SimpleSelectExpression($expression);
 -         } else if ($this->_lexer->lookahead['value'] == '(') {
 -             if ($peek['type'] == Lexer::T_SELECT) {
 -                 // Subselect
 -                 $this->match(Lexer::T_OPEN_PARENTHESIS);
 -                 $expression = $this->Subselect();
 -                 $this->match(Lexer::T_CLOSE_PARENTHESIS);
 -             } else {
 -                 // Shortcut: ScalarExpression => SimpleArithmeticExpression
 -                 $expression = $this->SimpleArithmeticExpression();
 -             }
 - 
 -             return new AST\SimpleSelectExpression($expression);
 -         }
 - 
 -         $this->_lexer->peek();
 - 
 -         $expression = $this->ScalarExpression();
 - 
 -         $expr = new AST\SimpleSelectExpression($expression);
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_AS)) {
 -             $this->match(Lexer::T_AS);
 -         }
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
 -             $token = $this->_lexer->lookahead;
 -             $resultVariable = $this->AliasResultVariable();
 -             $expr->fieldIdentificationVariable = $resultVariable;
 - 
 -             // Include AliasResultVariable in query components.
 -             $this->_queryComponents[$resultVariable] = array(
 -                 'resultvariable' => $expr,
 -                 'nestingLevel'   => $this->_nestingLevel,
 -                 'token'          => $token,
 -             );
 -         }
 - 
 -         return $expr;
 -     }
 - 
 -     /**
 -      * ConditionalExpression ::= ConditionalTerm {"OR" ConditionalTerm}*
 -      *
 -      * @return \Doctrine\ORM\Query\AST\ConditionalExpression
 -      */
 -     public function ConditionalExpression()
 -     {
 -         $conditionalTerms = array();
 -         $conditionalTerms[] = $this->ConditionalTerm();
 - 
 -         while ($this->_lexer->isNextToken(Lexer::T_OR)) {
 -             $this->match(Lexer::T_OR);
 -             $conditionalTerms[] = $this->ConditionalTerm();
 -         }
 - 
 -         // Phase 1 AST optimization: Prevent AST\ConditionalExpression
 -         // if only one AST\ConditionalTerm is defined
 -         if (count($conditionalTerms) == 1) {
 -             return $conditionalTerms[0];
 -         }
 - 
 -         return new AST\ConditionalExpression($conditionalTerms);
 -     }
 - 
 -     /**
 -      * ConditionalTerm ::= ConditionalFactor {"AND" ConditionalFactor}*
 -      *
 -      * @return \Doctrine\ORM\Query\AST\ConditionalTerm
 -      */
 -     public function ConditionalTerm()
 -     {
 -         $conditionalFactors = array();
 -         $conditionalFactors[] = $this->ConditionalFactor();
 - 
 -         while ($this->_lexer->isNextToken(Lexer::T_AND)) {
 -             $this->match(Lexer::T_AND);
 -             $conditionalFactors[] = $this->ConditionalFactor();
 -         }
 - 
 -         // Phase 1 AST optimization: Prevent AST\ConditionalTerm
 -         // if only one AST\ConditionalFactor is defined
 -         if (count($conditionalFactors) == 1) {
 -             return $conditionalFactors[0];
 -         }
 - 
 -         return new AST\ConditionalTerm($conditionalFactors);
 -     }
 - 
 -     /**
 -      * ConditionalFactor ::= ["NOT"] ConditionalPrimary
 -      *
 -      * @return \Doctrine\ORM\Query\AST\ConditionalFactor
 -      */
 -     public function ConditionalFactor()
 -     {
 -         $not = false;
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
 -             $this->match(Lexer::T_NOT);
 -             $not = true;
 -         }
 -         
 -         $conditionalPrimary = $this->ConditionalPrimary();
 - 
 -         // Phase 1 AST optimization: Prevent AST\ConditionalFactor
 -         // if only one AST\ConditionalPrimary is defined
 -         if ( ! $not) {
 -             return $conditionalPrimary;
 -         }
 - 
 -         $conditionalFactor = new AST\ConditionalFactor($conditionalPrimary);
 -         $conditionalFactor->not = $not;
 - 
 -         return $conditionalFactor;
 -     }
 - 
 -     /**
 -      * ConditionalPrimary ::= SimpleConditionalExpression | "(" ConditionalExpression ")"
 -      *
 -      * @return \Doctrine\ORM\Query\AST\ConditionalPrimary
 -      */
 -     public function ConditionalPrimary()
 -     {
 -         $condPrimary = new AST\ConditionalPrimary;
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
 -             // Peek beyond the matching closing paranthesis ')'
 -             $peek = $this->_peekBeyondClosingParenthesis();
 - 
 -             if (in_array($peek['value'], array("=",  "<", "<=", "<>", ">", ">=", "!=")) ||
 -                     $peek['type'] === Lexer::T_NOT ||
 -                     $peek['type'] === Lexer::T_BETWEEN ||
 -                     $peek['type'] === Lexer::T_LIKE ||
 -                     $peek['type'] === Lexer::T_IN ||
 -                     $peek['type'] === Lexer::T_IS ||
 -                     $peek['type'] === Lexer::T_EXISTS) {
 -                 $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression();
 -             } else {
 -                 $this->match(Lexer::T_OPEN_PARENTHESIS);
 -                 $condPrimary->conditionalExpression = $this->ConditionalExpression();
 -                 $this->match(Lexer::T_CLOSE_PARENTHESIS);
 -             }
 -         } else {
 -             $condPrimary->simpleConditionalExpression = $this->SimpleConditionalExpression();
 -         }
 - 
 -         return $condPrimary;
 -     }
 - 
 -     /**
 -      * SimpleConditionalExpression ::=
 -      *      ComparisonExpression | BetweenExpression | LikeExpression |
 -      *      InExpression | NullComparisonExpression | ExistsExpression |
 -      *      EmptyCollectionComparisonExpression | CollectionMemberExpression |
 -      *      InstanceOfExpression
 -      */
 -     public function SimpleConditionalExpression()
 -     {
 -         if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
 -             $token = $this->_lexer->glimpse();
 -         } else {
 -             $token = $this->_lexer->lookahead;
 -         }
 - 
 -         if ($token['type'] === Lexer::T_EXISTS) {
 -             return $this->ExistsExpression();
 -         }
 - 
 -         $peek = $this->_lexer->glimpse();
 - 
 -         if ($token['type'] === Lexer::T_IDENTIFIER || $token['type'] === Lexer::T_INPUT_PARAMETER) {
 -             if ($peek['value'] == '(') {
 -                 // Peek beyond the matching closing paranthesis ')'
 -                 $this->_lexer->peek();
 -                 $token = $this->_peekBeyondClosingParenthesis();
 -             } else {
 -                 // Peek beyond the PathExpression (or InputParameter)
 -                 $peek = $this->_lexer->peek();
 - 
 -                 while ($peek['value'] === '.') {
 -                     $this->_lexer->peek();
 -                     $peek = $this->_lexer->peek();
 -                 }
 - 
 -                 // Also peek beyond a NOT if there is one
 -                 if ($peek['type'] === Lexer::T_NOT) {
 -                     $peek = $this->_lexer->peek();
 -                 }
 - 
 -                 $token = $peek;
 - 
 -                 // We need to go even further in case of IS (differenciate between NULL and EMPTY)
 -                 $lookahead = $this->_lexer->peek();
 - 
 -                 // Also peek beyond a NOT if there is one
 -                 if ($lookahead['type'] === Lexer::T_NOT) {
 -                     $lookahead = $this->_lexer->peek();
 -                 }
 - 
 -                 $this->_lexer->resetPeek();
 -             }
 -         }
 - 
 -         switch ($token['type']) {
 -             case Lexer::T_BETWEEN:
 -                 return $this->BetweenExpression();
 -             case Lexer::T_LIKE:
 -                 return $this->LikeExpression();
 -             case Lexer::T_IN:
 -                 return $this->InExpression();
 -             case Lexer::T_INSTANCE:
 -                 return $this->InstanceOfExpression();
 -             case Lexer::T_IS:
 -                 if ($lookahead['type'] == Lexer::T_NULL) {
 -                     return $this->NullComparisonExpression();
 -                 }
 -                 return $this->EmptyCollectionComparisonExpression();
 -             case Lexer::T_MEMBER:
 -                 return $this->CollectionMemberExpression();
 -             default:
 -                 return $this->ComparisonExpression();
 -         }
 -     }
 - 
 -     /**
 -      * EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"
 -      *
 -      * @return \Doctrine\ORM\Query\AST\EmptyCollectionComparisonExpression
 -      */
 -     public function EmptyCollectionComparisonExpression()
 -     {
 -         $emptyColletionCompExpr = new AST\EmptyCollectionComparisonExpression(
 -             $this->CollectionValuedPathExpression()
 -         );
 -         $this->match(Lexer::T_IS);
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
 -             $this->match(Lexer::T_NOT);
 -             $emptyColletionCompExpr->not = true;
 -         }
 - 
 -         $this->match(Lexer::T_EMPTY);
 - 
 -         return $emptyColletionCompExpr;
 -     }
 - 
 -     /**
 -      * CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression
 -      *
 -      * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression
 -      * SimpleEntityExpression ::= IdentificationVariable | InputParameter
 -      *
 -      * @return \Doctrine\ORM\Query\AST\CollectionMemberExpression
 -      */
 -     public function CollectionMemberExpression()
 -     {
 -         $not = false;
 - 
 -         $entityExpr = $this->EntityExpression();
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
 -             $not = true;
 -             $this->match(Lexer::T_NOT);
 -         }
 - 
 -         $this->match(Lexer::T_MEMBER);
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_OF)) {
 -             $this->match(Lexer::T_OF);
 -         }
 - 
 -         $collMemberExpr = new AST\CollectionMemberExpression(
 -             $entityExpr, $this->CollectionValuedPathExpression()
 -         );
 -         $collMemberExpr->not = $not;
 - 
 -         return $collMemberExpr;
 -     }
 - 
 -     /**
 -      * Literal ::= string | char | integer | float | boolean
 -      *
 -      * @return string
 -      */
 -     public function Literal()
 -     {
 -         switch ($this->_lexer->lookahead['type']) {
 -             case Lexer::T_STRING:
 -                 $this->match(Lexer::T_STRING);
 -                 return new AST\Literal(AST\Literal::STRING, $this->_lexer->token['value']);
 - 
 -             case Lexer::T_INTEGER:
 -             case Lexer::T_FLOAT:
 -                 $this->match(
 -                     $this->_lexer->isNextToken(Lexer::T_INTEGER) ? Lexer::T_INTEGER : Lexer::T_FLOAT
 -                 );
 -                 return new AST\Literal(AST\Literal::NUMERIC, $this->_lexer->token['value']);
 - 
 -             case Lexer::T_TRUE:
 -             case Lexer::T_FALSE:
 -                 $this->match(
 -                     $this->_lexer->isNextToken(Lexer::T_TRUE) ? Lexer::T_TRUE : Lexer::T_FALSE
 -                 );
 -                 return new AST\Literal(AST\Literal::BOOLEAN, $this->_lexer->token['value']);
 - 
 -             default:
 -                 $this->syntaxError('Literal');
 -         }
 -     }
 - 
 -     /**
 -      * InParameter ::= Literal | InputParameter
 -      *
 -      * @return string | \Doctrine\ORM\Query\AST\InputParameter
 -      */
 -     public function InParameter()
 -     {
 -         if ($this->_lexer->lookahead['type'] == Lexer::T_INPUT_PARAMETER) {
 -             return $this->InputParameter();
 -         }
 - 
 -         return $this->Literal();
 -     }
 - 
 -     /**
 -      * InputParameter ::= PositionalParameter | NamedParameter
 -      *
 -      * @return \Doctrine\ORM\Query\AST\InputParameter
 -      */
 -     public function InputParameter()
 -     {
 -         $this->match(Lexer::T_INPUT_PARAMETER);
 - 
 -         return new AST\InputParameter($this->_lexer->token['value']);
 -     }
 - 
 -     /**
 -      * ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")"
 -      *
 -      * @return \Doctrine\ORM\Query\AST\ArithmeticExpression
 -      */
 -     public function ArithmeticExpression()
 -     {
 -         $expr = new AST\ArithmeticExpression;
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
 -             $peek = $this->_lexer->glimpse();
 - 
 -             if ($peek['type'] === Lexer::T_SELECT) {
 -                 $this->match(Lexer::T_OPEN_PARENTHESIS);
 -                 $expr->subselect = $this->Subselect();
 -                 $this->match(Lexer::T_CLOSE_PARENTHESIS);
 - 
 -                 return $expr;
 -             }
 -         }
 - 
 -         $expr->simpleArithmeticExpression = $this->SimpleArithmeticExpression();
 - 
 -         return $expr;
 -     }
 - 
 -     /**
 -      * SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}*
 -      *
 -      * @return \Doctrine\ORM\Query\AST\SimpleArithmeticExpression
 -      */
 -     public function SimpleArithmeticExpression()
 -     {
 -         $terms = array();
 -         $terms[] = $this->ArithmeticTerm();
 - 
 -         while (($isPlus = $this->_lexer->isNextToken(Lexer::T_PLUS)) || $this->_lexer->isNextToken(Lexer::T_MINUS)) {
 -             $this->match(($isPlus) ? Lexer::T_PLUS : Lexer::T_MINUS);
 - 
 -             $terms[] = $this->_lexer->token['value'];
 -             $terms[] = $this->ArithmeticTerm();
 -         }
 - 
 -         // Phase 1 AST optimization: Prevent AST\SimpleArithmeticExpression
 -         // if only one AST\ArithmeticTerm is defined
 -         if (count($terms) == 1) {
 -             return $terms[0];
 -         }
 - 
 -         return new AST\SimpleArithmeticExpression($terms);
 -     }
 - 
 -     /**
 -      * ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}*
 -      *
 -      * @return \Doctrine\ORM\Query\AST\ArithmeticTerm
 -      */
 -     public function ArithmeticTerm()
 -     {
 -         $factors = array();
 -         $factors[] = $this->ArithmeticFactor();
 - 
 -         while (($isMult = $this->_lexer->isNextToken(Lexer::T_MULTIPLY)) || $this->_lexer->isNextToken(Lexer::T_DIVIDE)) {
 -             $this->match(($isMult) ? Lexer::T_MULTIPLY : Lexer::T_DIVIDE);
 - 
 -             $factors[] = $this->_lexer->token['value'];
 -             $factors[] = $this->ArithmeticFactor();
 -         }
 - 
 -         // Phase 1 AST optimization: Prevent AST\ArithmeticTerm
 -         // if only one AST\ArithmeticFactor is defined
 -         if (count($factors) == 1) {
 -             return $factors[0];
 -         }
 - 
 -         return new AST\ArithmeticTerm($factors);
 -     }
 - 
 -     /**
 -      * ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary
 -      *
 -      * @return \Doctrine\ORM\Query\AST\ArithmeticFactor
 -      */
 -     public function ArithmeticFactor()
 -     {
 -         $sign = null;
 - 
 -         if (($isPlus = $this->_lexer->isNextToken(Lexer::T_PLUS)) || $this->_lexer->isNextToken(Lexer::T_MINUS)) {
 -             $this->match(($isPlus) ? Lexer::T_PLUS : Lexer::T_MINUS);
 -             $sign = $isPlus;
 -         }
 -         
 -         $primary = $this->ArithmeticPrimary();
 - 
 -         // Phase 1 AST optimization: Prevent AST\ArithmeticFactor
 -         // if only one AST\ArithmeticPrimary is defined
 -         if ($sign === null) {
 -             return $primary;
 -         }
 - 
 -         return new AST\ArithmeticFactor($primary, $sign);
 -     }
 - 
 -     /**
 -      * ArithmeticPrimary ::= SingleValuedPathExpression | Literal | "(" SimpleArithmeticExpression ")"
 -      *          | FunctionsReturningNumerics | AggregateExpression | FunctionsReturningStrings
 -      *          | FunctionsReturningDatetime | IdentificationVariable | ResultVariable 
 -      */
 -     public function ArithmeticPrimary()
 -     {
 -         if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
 -             $this->match(Lexer::T_OPEN_PARENTHESIS);
 -             $expr = $this->SimpleArithmeticExpression();
 - 
 -             $this->match(Lexer::T_CLOSE_PARENTHESIS);
 - 
 -             return $expr;
 -         }
 - 
 -         switch ($this->_lexer->lookahead['type']) {
 -             case Lexer::T_IDENTIFIER:
 -                 $peek = $this->_lexer->glimpse();
 - 
 -                 if ($peek['value'] == '(') {
 -                     return $this->FunctionDeclaration();
 -                 }
 - 
 -                 if ($peek['value'] == '.') {
 -                     return $this->SingleValuedPathExpression();
 -                 }
 -                 
 -                 if (isset($this->_queryComponents[$this->_lexer->lookahead['value']]['resultVariable'])) {
 -                     return $this->ResultVariable();
 -                 }
 -                 
 -                 return $this->StateFieldPathExpression();
 - 
 -             case Lexer::T_INPUT_PARAMETER:
 -                 return $this->InputParameter();
 - 
 -             default:
 -                 $peek = $this->_lexer->glimpse();
 - 
 -                 if ($peek['value'] == '(') {
 -                     if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
 -                         return $this->AggregateExpression();
 -                     }
 - 
 -                     return $this->FunctionDeclaration();
 -                 } else {
 -                     return $this->Literal();
 -                 }
 -         }
 -     }
 - 
 -     /**
 -      * StringExpression ::= StringPrimary | "(" Subselect ")"
 -      *
 -      * @return \Doctrine\ORM\Query\AST\StringPrimary |
 -      *         \Doctrine]ORM\Query\AST\Subselect
 -      */
 -     public function StringExpression()
 -     {
 -         if ($this->_lexer->isNextToken(Lexer::T_OPEN_PARENTHESIS)) {
 -             $peek = $this->_lexer->glimpse();
 - 
 -             if ($peek['type'] === Lexer::T_SELECT) {
 -                 $this->match(Lexer::T_OPEN_PARENTHESIS);
 -                 $expr = $this->Subselect();
 -                 $this->match(Lexer::T_CLOSE_PARENTHESIS);
 - 
 -                 return $expr;
 -             }
 -         }
 - 
 -         return $this->StringPrimary();
 -     }
 - 
 -     /**
 -      * StringPrimary ::= StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression
 -      */
 -     public function StringPrimary()
 -     {
 -         if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
 -             $peek = $this->_lexer->glimpse();
 - 
 -             if ($peek['value'] == '.') {
 -                 return $this->StateFieldPathExpression();
 -             } else if ($peek['value'] == '(') {
 -                 // do NOT directly go to FunctionsReturningString() because it doesnt check for custom functions.
 -                 return $this->FunctionDeclaration();
 -             } else {
 -                 $this->syntaxError("'.' or '('");
 -             }
 -         } else if ($this->_lexer->isNextToken(Lexer::T_STRING)) {
 -             $this->match(Lexer::T_STRING);
 - 
 -             return $this->_lexer->token['value'];
 -         } else if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
 -             return $this->InputParameter();
 -         } else if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
 -             return $this->AggregateExpression();
 -         }
 - 
 -         $this->syntaxError('StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression');
 -     }
 - 
 -     /**
 -      * EntityExpression ::= SingleValuedAssociationPathExpression | SimpleEntityExpression
 -      *
 -      * @return \Doctrine\ORM\Query\AST\SingleValuedAssociationPathExpression |
 -      *         \Doctrine\ORM\Query\AST\SimpleEntityExpression
 -      */
 -     public function EntityExpression()
 -     {
 -         $glimpse = $this->_lexer->glimpse();
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER) && $glimpse['value'] === '.') {
 -             return $this->SingleValuedAssociationPathExpression();
 -         }
 - 
 -         return $this->SimpleEntityExpression();
 -     }
 - 
 -     /**
 -      * SimpleEntityExpression ::= IdentificationVariable | InputParameter
 -      *
 -      * @return string | \Doctrine\ORM\Query\AST\InputParameter
 -      */
 -     public function SimpleEntityExpression()
 -     {
 -         if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
 -             return $this->InputParameter();
 -         }
 - 
 -         return $this->IdentificationVariable();
 -     }
 - 
 -     /**
 -      * AggregateExpression ::=
 -      *  ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" |
 -      *  "COUNT" "(" ["DISTINCT"] (IdentificationVariable | SingleValuedPathExpression) ")"
 -      *
 -      * @return \Doctrine\ORM\Query\AST\AggregateExpression
 -      */
 -     public function AggregateExpression()
 -     {
 -         $isDistinct = false;
 -         $functionName = '';
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_COUNT)) {
 -             $this->match(Lexer::T_COUNT);
 -             $functionName = $this->_lexer->token['value'];
 -             $this->match(Lexer::T_OPEN_PARENTHESIS);
 - 
 -             if ($this->_lexer->isNextToken(Lexer::T_DISTINCT)) {
 -                 $this->match(Lexer::T_DISTINCT);
 -                 $isDistinct = true;
 -             }
 - 
 -             $pathExp = $this->SingleValuedPathExpression();
 -             $this->match(Lexer::T_CLOSE_PARENTHESIS);
 -         } else {
 -             if ($this->_lexer->isNextToken(Lexer::T_AVG)) {
 -                 $this->match(Lexer::T_AVG);
 -             } else if ($this->_lexer->isNextToken(Lexer::T_MAX)) {
 -                 $this->match(Lexer::T_MAX);
 -             } else if ($this->_lexer->isNextToken(Lexer::T_MIN)) {
 -                 $this->match(Lexer::T_MIN);
 -             } else if ($this->_lexer->isNextToken(Lexer::T_SUM)) {
 -                 $this->match(Lexer::T_SUM);
 -             } else {
 -                 $this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT');
 -             }
 - 
 -             $functionName = $this->_lexer->token['value'];
 -             $this->match(Lexer::T_OPEN_PARENTHESIS);
 -             $pathExp = $this->SimpleArithmeticExpression();
 -             $this->match(Lexer::T_CLOSE_PARENTHESIS);
 -         }
 - 
 -         return new AST\AggregateExpression($functionName, $pathExp, $isDistinct);
 -     }
 - 
 -     /**
 -      * QuantifiedExpression ::= ("ALL" | "ANY" | "SOME") "(" Subselect ")"
 -      *
 -      * @return \Doctrine\ORM\Query\AST\QuantifiedExpression
 -      */
 -     public function QuantifiedExpression()
 -     {
 -         $type = '';
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_ALL)) {
 -             $this->match(Lexer::T_ALL);
 -             $type = 'ALL';
 -         } else if ($this->_lexer->isNextToken(Lexer::T_ANY)) {
 -             $this->match(Lexer::T_ANY);
 -              $type = 'ANY';
 -         } else if ($this->_lexer->isNextToken(Lexer::T_SOME)) {
 -             $this->match(Lexer::T_SOME);
 -              $type = 'SOME';
 -         } else {
 -             $this->syntaxError('ALL, ANY or SOME');
 -         }
 - 
 -         $this->match(Lexer::T_OPEN_PARENTHESIS);
 -         $qExpr = new AST\QuantifiedExpression($this->Subselect());
 -         $qExpr->type = $type;
 -         $this->match(Lexer::T_CLOSE_PARENTHESIS);
 - 
 -         return $qExpr;
 -     }
 - 
 -     /**
 -      * BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression
 -      *
 -      * @return \Doctrine\ORM\Query\AST\BetweenExpression
 -      */
 -     public function BetweenExpression()
 -     {
 -         $not = false;
 -         $arithExpr1 = $this->ArithmeticExpression();
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
 -             $this->match(Lexer::T_NOT);
 -             $not = true;
 -         }
 - 
 -         $this->match(Lexer::T_BETWEEN);
 -         $arithExpr2 = $this->ArithmeticExpression();
 -         $this->match(Lexer::T_AND);
 -         $arithExpr3 = $this->ArithmeticExpression();
 - 
 -         $betweenExpr = new AST\BetweenExpression($arithExpr1, $arithExpr2, $arithExpr3);
 -         $betweenExpr->not = $not;
 - 
 -         return $betweenExpr;
 -     }
 - 
 -     /**
 -      * ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression )
 -      *
 -      * @return \Doctrine\ORM\Query\AST\ComparisonExpression
 -      */
 -     public function ComparisonExpression()
 -     {
 -         $peek = $this->_lexer->glimpse();
 - 
 -         $leftExpr = $this->ArithmeticExpression();
 -         $operator = $this->ComparisonOperator();
 - 
 -         if ($this->_isNextAllAnySome()) {
 -             $rightExpr = $this->QuantifiedExpression();
 -         } else {
 -             $rightExpr = $this->ArithmeticExpression();
 -         }
 - 
 -         return new AST\ComparisonExpression($leftExpr, $operator, $rightExpr);
 -     }
 - 
 -     /**
 -      * InExpression ::= SingleValuedPathExpression ["NOT"] "IN" "(" (InParameter {"," InParameter}* | Subselect) ")"
 -      *
 -      * @return \Doctrine\ORM\Query\AST\InExpression
 -      */
 -     public function InExpression()
 -     {
 -         $inExpression = new AST\InExpression($this->SingleValuedPathExpression());
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
 -             $this->match(Lexer::T_NOT);
 -             $inExpression->not = true;
 -         }
 - 
 -         $this->match(Lexer::T_IN);
 -         $this->match(Lexer::T_OPEN_PARENTHESIS);
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_SELECT)) {
 -             $inExpression->subselect = $this->Subselect();
 -         } else {
 -             $literals = array();
 -             $literals[] = $this->InParameter();
 - 
 -             while ($this->_lexer->isNextToken(Lexer::T_COMMA)) {
 -                 $this->match(Lexer::T_COMMA);
 -                 $literals[] = $this->InParameter();
 -             }
 - 
 -             $inExpression->literals = $literals;
 -         }
 - 
 -         $this->match(Lexer::T_CLOSE_PARENTHESIS);
 - 
 -         return $inExpression;
 -     }
 - 
 -     /**
 -      * InstanceOfExpression ::= IdentificationVariable ["NOT"] "INSTANCE" ["OF"] (AbstractSchemaName | InputParameter)
 -      *
 -      * @return \Doctrine\ORM\Query\AST\InstanceOfExpression
 -      */
 -     public function InstanceOfExpression()
 -     {
 -         $instanceOfExpression = new AST\InstanceOfExpression($this->IdentificationVariable());
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
 -             $this->match(Lexer::T_NOT);
 -             $instanceOfExpression->not = true;
 -         }
 - 
 -         $this->match(Lexer::T_INSTANCE);
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_OF)) {
 -             $this->match(Lexer::T_OF);
 -         }
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
 -             $this->match(Lexer::T_INPUT_PARAMETER);
 -             $exprValue = new AST\InputParameter($this->_lexer->token['value']);
 -         } else {
 -             $exprValue = $this->AliasIdentificationVariable();
 -         }
 - 
 -         $instanceOfExpression->value = $exprValue;
 -         
 -         return $instanceOfExpression;
 -     }
 - 
 -     /**
 -      * LikeExpression ::= StringExpression ["NOT"] "LIKE" (string | input_parameter) ["ESCAPE" char]
 -      *
 -      * @return \Doctrine\ORM\Query\AST\LikeExpression
 -      */
 -     public function LikeExpression()
 -     {
 -         $stringExpr = $this->StringExpression();
 -         $not = false;
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
 -             $this->match(Lexer::T_NOT);
 -             $not = true;
 -         }
 - 
 -         $this->match(Lexer::T_LIKE);
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
 -             $this->match(Lexer::T_INPUT_PARAMETER);
 -             $stringPattern = new AST\InputParameter($this->_lexer->token['value']);
 -         } else {
 -             $this->match(Lexer::T_STRING);
 -             $stringPattern = $this->_lexer->token['value'];
 -         }
 - 
 -         $escapeChar = null;
 - 
 -         if ($this->_lexer->lookahead['type'] === Lexer::T_ESCAPE) {
 -             $this->match(Lexer::T_ESCAPE);
 -             $this->match(Lexer::T_STRING);
 -             $escapeChar = $this->_lexer->token['value'];
 -         }
 - 
 -         $likeExpr = new AST\LikeExpression($stringExpr, $stringPattern, $escapeChar);
 -         $likeExpr->not = $not;
 - 
 -         return $likeExpr;
 -     }
 - 
 -     /**
 -      * NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL"
 -      *
 -      * @return \Doctrine\ORM\Query\AST\NullComparisonExpression
 -      */
 -     public function NullComparisonExpression()
 -     {
 -         if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
 -             $this->match(Lexer::T_INPUT_PARAMETER);
 -             $expr = new AST\InputParameter($this->_lexer->token['value']);
 -         } else {
 -             $expr = $this->SingleValuedPathExpression();
 -         }
 - 
 -         $nullCompExpr = new AST\NullComparisonExpression($expr);
 -         $this->match(Lexer::T_IS);
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
 -             $this->match(Lexer::T_NOT);
 -             $nullCompExpr->not = true;
 -         }
 - 
 -         $this->match(Lexer::T_NULL);
 - 
 -         return $nullCompExpr;
 -     }
 - 
 -     /**
 -      * ExistsExpression ::= ["NOT"] "EXISTS" "(" Subselect ")"
 -      *
 -      * @return \Doctrine\ORM\Query\AST\ExistsExpression
 -      */
 -     public function ExistsExpression()
 -     {
 -         $not = false;
 - 
 -         if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
 -             $this->match(Lexer::T_NOT);
 -             $not = true;
 -         }
 - 
 -         $this->match(Lexer::T_EXISTS);
 -         $this->match(Lexer::T_OPEN_PARENTHESIS);
 -         $existsExpression = new AST\ExistsExpression($this->Subselect());
 -         $existsExpression->not = $not;
 -         $this->match(Lexer::T_CLOSE_PARENTHESIS);
 - 
 -         return $existsExpression;
 -     }
 - 
 -     /**
 -      * ComparisonOperator ::= "=" | "<" | "<=" | "<>" | ">" | ">=" | "!="
 -      *
 -      * @return string
 -      */
 -     public function ComparisonOperator()
 -     {
 -         switch ($this->_lexer->lookahead['value']) {
 -             case '=':
 -                 $this->match(Lexer::T_EQUALS);
 - 
 -                 return '=';
 - 
 -             case '<':
 -                 $this->match(Lexer::T_LOWER_THAN);
 -                 $operator = '<';
 - 
 -                 if ($this->_lexer->isNextToken(Lexer::T_EQUALS)) {
 -                     $this->match(Lexer::T_EQUALS);
 -                     $operator .= '=';
 -                 } else if ($this->_lexer->isNextToken(Lexer::T_GREATER_THAN)) {
 -                     $this->match(Lexer::T_GREATER_THAN);
 -                     $operator .= '>';
 -                 }
 - 
 -                 return $operator;
 - 
 -             case '>':
 -                 $this->match(Lexer::T_GREATER_THAN);
 -                 $operator = '>';
 - 
 -                 if ($this->_lexer->isNextToken(Lexer::T_EQUALS)) {
 -                     $this->match(Lexer::T_EQUALS);
 -                     $operator .= '=';
 -                 }
 - 
 -                 return $operator;
 - 
 -             case '!':
 -                 $this->match(Lexer::T_NEGATE);
 -                 $this->match(Lexer::T_EQUALS);
 - 
 -                 return '<>';
 - 
 -             default:
 -                 $this->syntaxError('=, <, <=, <>, >, >=, !=');
 -         }
 -     }
 - 
 -     /**
 -      * FunctionDeclaration ::= FunctionsReturningStrings | FunctionsReturningNumerics | FunctionsReturningDatetime
 -      */
 -     public function FunctionDeclaration()
 -     {
 -         $token = $this->_lexer->lookahead;
 -         $funcName = strtolower($token['value']);
 - 
 -         // Check for built-in functions first!
 -         if (isset(self::$_STRING_FUNCTIONS[$funcName])) {
 -             return $this->FunctionsReturningStrings();
 -         } else if (isset(self::$_NUMERIC_FUNCTIONS[$funcName])) {
 -             return $this->FunctionsReturningNumerics();
 -         } else if (isset(self::$_DATETIME_FUNCTIONS[$funcName])) {
 -             return $this->FunctionsReturningDatetime();
 -         }
 - 
 -         // Check for custom functions afterwards
 -         $config = $this->_em->getConfiguration();
 - 
 -         if ($config->getCustomStringFunction($funcName) !== null) {
 -             return $this->CustomFunctionsReturningStrings();
 -         } else if ($config->getCustomNumericFunction($funcName) !== null) {
 -             return $this->CustomFunctionsReturningNumerics();
 -         } else if ($config->getCustomDatetimeFunction($funcName) !== null) {
 -             return $this->CustomFunctionsReturningDatetime();
 -         }
 - 
 -         $this->syntaxError('known function', $token);
 -     }
 - 
 -     /**
 -      * FunctionsReturningNumerics ::=
 -      *      "LENGTH" "(" StringPrimary ")" |
 -      *      "LOCATE" "(" StringPrimary "," StringPrimary ["," SimpleArithmeticExpression]")" |
 -      *      "ABS" "(" SimpleArithmeticExpression ")" |
 -      *      "SQRT" "(" SimpleArithmeticExpression ")" |
 -      *      "MOD" "(" SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
 -      *      "SIZE" "(" CollectionValuedPathExpression ")"
 -      */
 -     public function FunctionsReturningNumerics()
 -     {
 -         $funcNameLower = strtolower($this->_lexer->lookahead['value']);
 -         $funcClass = self::$_NUMERIC_FUNCTIONS[$funcNameLower];
 -         $function = new $funcClass($funcNameLower);
 -         $function->parse($this);
 - 
 -         return $function;
 -     }
 - 
 -     public function CustomFunctionsReturningNumerics()
 -     {
 -         $funcName = strtolower($this->_lexer->lookahead['value']);
 -         // getCustomNumericFunction is case-insensitive
 -         $funcClass = $this->_em->getConfiguration()->getCustomNumericFunction($funcName);
 -         $function = new $funcClass($funcName);
 -         $function->parse($this);
 - 
 -         return $function;
 -     }
 - 
 -     /**
 -      * FunctionsReturningDateTime ::= "CURRENT_DATE" | "CURRENT_TIME" | "CURRENT_TIMESTAMP"
 -      */
 -     public function FunctionsReturningDatetime()
 -     {
 -         $funcNameLower = strtolower($this->_lexer->lookahead['value']);
 -         $funcClass = self::$_DATETIME_FUNCTIONS[$funcNameLower];
 -         $function = new $funcClass($funcNameLower);
 -         $function->parse($this);
 - 
 -         return $function;
 -     }
 - 
 -     public function CustomFunctionsReturningDatetime()
 -     {
 -         $funcName = $this->_lexer->lookahead['value'];
 -         // getCustomDatetimeFunction is case-insensitive
 -         $funcClass = $this->_em->getConfiguration()->getCustomDatetimeFunction($funcName);
 -         $function = new $funcClass($funcName);
 -         $function->parse($this);
 - 
 -         return $function;
 -     }
 - 
 -     /**
 -      * FunctionsReturningStrings ::=
 -      *   "CONCAT" "(" StringPrimary "," StringPrimary ")" |
 -      *   "SUBSTRING" "(" StringPrimary "," SimpleArithmeticExpression "," SimpleArithmeticExpression ")" |
 -      *   "TRIM" "(" [["LEADING" | "TRAILING" | "BOTH"] [char] "FROM"] StringPrimary ")" |
 -      *   "LOWER" "(" StringPrimary ")" |
 -      *   "UPPER" "(" StringPrimary ")"
 -      */
 -     public function FunctionsReturningStrings()
 -     {
 -         $funcNameLower = strtolower($this->_lexer->lookahead['value']);
 -         $funcClass = self::$_STRING_FUNCTIONS[$funcNameLower];
 -         $function = new $funcClass($funcNameLower);
 -         $function->parse($this);
 - 
 -         return $function;
 -     }
 - 
 -     public function CustomFunctionsReturningStrings()
 -     {
 -         $funcName = $this->_lexer->lookahead['value'];
 -         // getCustomStringFunction is case-insensitive
 -         $funcClass = $this->_em->getConfiguration()->getCustomStringFunction($funcName);
 -         $function = new $funcClass($funcName);
 -         $function->parse($this);
 - 
 -         return $function;
 -     }
 - }
 
 
  |