[2.0] Some more parser work.
This commit is contained in:
parent
c4e22ba87a
commit
bc379103c3
@ -16,7 +16,7 @@
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
@ -26,7 +26,7 @@ namespace Doctrine\ORM\Query\AST;
|
||||
*
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.phpdoctrine.org
|
||||
* @link http://www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
|
56
lib/Doctrine/ORM/Query/AST/InExpression.php
Normal file
56
lib/Doctrine/ORM/Query/AST/InExpression.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* InExpression ::= StateFieldPathExpression ["NOT"] "IN" "(" (Literal {"," Literal}* | Subselect) ")"
|
||||
*
|
||||
* @author robo
|
||||
*/
|
||||
class InExpression extends Node
|
||||
{
|
||||
private $_pathExpression;
|
||||
private $_not = false;
|
||||
private $_literals = array();
|
||||
private $_subselect;
|
||||
|
||||
public function __construct($pathExpression)
|
||||
{
|
||||
$this->_pathExpression = $pathExpression;
|
||||
}
|
||||
|
||||
public function setLiterals(array $literals)
|
||||
{
|
||||
$this->_literals = $literals;
|
||||
}
|
||||
|
||||
public function getLiterals()
|
||||
{
|
||||
return $this->_literals;
|
||||
}
|
||||
|
||||
public function setSubselect($subselect)
|
||||
{
|
||||
$this->_subselect = $subselect;
|
||||
}
|
||||
|
||||
public function getSubselect()
|
||||
{
|
||||
return $this->_subselect;
|
||||
}
|
||||
|
||||
public function setNot($bool)
|
||||
{
|
||||
$this->_not = $bool;
|
||||
}
|
||||
|
||||
public function getNot()
|
||||
{
|
||||
return $this->_not;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query;
|
||||
@ -28,7 +28,7 @@ namespace Doctrine\ORM\Query;
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
@ -174,7 +174,6 @@ class Lexer
|
||||
|
||||
if (defined($name)) {
|
||||
$type = constant($name);
|
||||
|
||||
if ($type > 100) {
|
||||
return $type;
|
||||
}
|
||||
@ -319,68 +318,64 @@ class Lexer
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Doc
|
||||
* Resets the lexer position on the input to the given position.
|
||||
*/
|
||||
public function resetPosition($position = 0)
|
||||
{
|
||||
$this->_position = $position;
|
||||
}
|
||||
|
||||
private function _addKeyword($token, $value)
|
||||
{
|
||||
$this->_keywordsTable[$token] = $value;
|
||||
}
|
||||
|
||||
public function getLiteral($token)
|
||||
{
|
||||
if ( ! $this->_keywordsTable) {
|
||||
$this->_addKeyword(self::T_ALL, "ALL");
|
||||
$this->_addKeyword(self::T_AND, "AND");
|
||||
$this->_addKeyword(self::T_ANY, "ANY");
|
||||
$this->_addKeyword(self::T_AS, "AS");
|
||||
$this->_addKeyword(self::T_ASC, "ASC");
|
||||
$this->_addKeyword(self::T_AVG, "AVG");
|
||||
$this->_addKeyword(self::T_BETWEEN, "BETWEEN");
|
||||
$this->_addKeyword(self::T_BY, "BY");
|
||||
$this->_addKeyword(self::T_COMMA, ",");
|
||||
$this->_addKeyword(self::T_COUNT, "COUNT");
|
||||
$this->_addKeyword(self::T_DELETE, "DELETE");
|
||||
$this->_addKeyword(self::T_DESC, "DESC");
|
||||
$this->_addKeyword(self::T_DISTINCT, "DISTINCT");
|
||||
$this->_addKeyword(self::T_DOT, ".");
|
||||
$this->_addKeyword(self::T_ESCAPE, "ESPACE");
|
||||
$this->_addKeyword(self::T_EXISTS, "EXISTS");
|
||||
$this->_addKeyword(self::T_FALSE, "FALSE");
|
||||
$this->_addKeyword(self::T_FROM, "FROM");
|
||||
$this->_addKeyword(self::T_GROUP, "GROUP");
|
||||
$this->_addKeyword(self::T_HAVING, "HAVING");
|
||||
$this->_addKeyword(self::T_IN, "IN");
|
||||
$this->_addKeyword(self::T_INDEX, "INDEX");
|
||||
$this->_addKeyword(self::T_INNER, "INNER");
|
||||
$this->_addKeyword(self::T_IS, "IS");
|
||||
$this->_addKeyword(self::T_JOIN, "JOIN");
|
||||
$this->_addKeyword(self::T_LEFT, "LEFT");
|
||||
$this->_addKeyword(self::T_LIKE, "LIKE");
|
||||
$this->_addKeyword(self::T_LIMIT, "LIMIT");
|
||||
$this->_addKeyword(self::T_MAX, "MAX");
|
||||
$this->_addKeyword(self::T_MIN, "MIN");
|
||||
$this->_addKeyword(self::T_MOD, "MOD");
|
||||
$this->_addKeyword(self::T_NOT, "NOT");
|
||||
$this->_addKeyword(self::T_NULL, "NULL");
|
||||
$this->_addKeyword(self::T_OFFSET, "OFFSET");
|
||||
$this->_addKeyword(self::T_ON, "ON");
|
||||
$this->_addKeyword(self::T_OR, "OR");
|
||||
$this->_addKeyword(self::T_ORDER, "ORDER");
|
||||
$this->_addKeyword(self::T_OUTER, "OUTER");
|
||||
$this->_addKeyword(self::T_SELECT, "SELECT");
|
||||
$this->_addKeyword(self::T_SET, "SET");
|
||||
$this->_addKeyword(self::T_SIZE, "SIZE");
|
||||
$this->_addKeyword(self::T_SOME, "SOME");
|
||||
$this->_addKeyword(self::T_SUM, "SUM");
|
||||
$this->_addKeyword(self::T_TRUE, "TRUE");
|
||||
$this->_addKeyword(self::T_UPDATE, "UPDATE");
|
||||
$this->_addKeyword(self::T_WHERE, "WHERE");
|
||||
$this->_addKeyword(self::T_WITH, "WITH");
|
||||
$this->_keywordsTable = array(
|
||||
self::T_ALL => "ALL",
|
||||
self::T_AND => "AND",
|
||||
self::T_ANY => "ANY",
|
||||
self::T_AS => "AS",
|
||||
self::T_ASC => "ASC",
|
||||
self::T_AVG => "AVG",
|
||||
self::T_BETWEEN => "BETWEEN",
|
||||
self::T_BY => "BY",
|
||||
self::T_COMMA => ",",
|
||||
self::T_COUNT => "COUNT",
|
||||
self::T_DELETE => "DELETE",
|
||||
self::T_DESC => "DESC",
|
||||
self::T_DISTINCT => "DISTINCT",
|
||||
self::T_DOT => ".",
|
||||
self::T_ESCAPE => "ESCAPE",
|
||||
self::T_EXISTS => "EXISTS",
|
||||
self::T_FALSE => "FALSE",
|
||||
self::T_FROM => "FROM",
|
||||
self::T_GROUP => "GROUP",
|
||||
self::T_HAVING => "HAVING",
|
||||
self::T_IN => "IN",
|
||||
self::T_INDEX => "INDEX",
|
||||
self::T_INNER => "INNER",
|
||||
self::T_IS => "IS",
|
||||
self::T_JOIN => "JOIN",
|
||||
self::T_LEFT => "LEFT",
|
||||
self::T_LIKE => "LIKE",
|
||||
self::T_LIMIT => "LIMIT",
|
||||
self::T_MAX => "MAX",
|
||||
self::T_MIN => "MIN",
|
||||
self::T_MOD => "MOD",
|
||||
self::T_NOT => "NOT",
|
||||
self::T_NULL => "NULL",
|
||||
self::T_OFFSET => "OFFSET",
|
||||
self::T_ON => "ON",
|
||||
self::T_OR => "OR",
|
||||
self::T_ORDER => "ORDER",
|
||||
self::T_OUTER => "OUTER",
|
||||
self::T_SELECT => "SELECT",
|
||||
self::T_SET => "SET",
|
||||
self::T_SIZE => "SIZE",
|
||||
self::T_SOME => "SOME",
|
||||
self::T_SUM => "SUM",
|
||||
self::T_TRUE => "TRUE",
|
||||
self::T_UPDATE => "UPDATE",
|
||||
self::T_WHERE => "WHERE",
|
||||
self::T_WITH => "WITH");
|
||||
}
|
||||
return isset($this->_keywordsTable[$token])
|
||||
? $this->_keywordsTable[$token]
|
||||
|
@ -319,8 +319,6 @@ class Parser
|
||||
|
||||
/**
|
||||
* QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
|
||||
*
|
||||
* @return <type>
|
||||
*/
|
||||
private function _QueryLanguage()
|
||||
{
|
||||
@ -346,8 +344,6 @@ class Parser
|
||||
|
||||
/**
|
||||
* SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
|
||||
*
|
||||
* @return <type>
|
||||
*/
|
||||
private function _SelectStatement()
|
||||
{
|
||||
@ -427,11 +423,17 @@ class Parser
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* UpdateStatement ::= UpdateClause [WhereClause]
|
||||
*/
|
||||
private function _UpdateStatement()
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* DeleteStatement ::= DeleteClause [WhereClause]
|
||||
*/
|
||||
private function _DeleteStatement()
|
||||
{
|
||||
//TODO
|
||||
@ -496,7 +498,7 @@ class Parser
|
||||
if ($this->_lexer->isNextToken(Lexer::T_AS)) {
|
||||
$this->match(Lexer::T_AS);
|
||||
$fieldIdentificationVariable = $this->_FieldAliasIdentificationVariable();
|
||||
} elseif ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
} else if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
$fieldIdentificationVariable = $this->_FieldAliasIdentificationVariable();
|
||||
}
|
||||
} else {
|
||||
@ -677,10 +679,7 @@ class Parser
|
||||
$join = new AST\Join($joinType, $joinPathExpression, $aliasIdentificationVariable);
|
||||
|
||||
// Check Join where type
|
||||
if (
|
||||
$this->_lexer->isNextToken(Lexer::T_ON) ||
|
||||
$this->_lexer->isNextToken(Lexer::T_WITH)
|
||||
) {
|
||||
if ($this->_lexer->isNextToken(Lexer::T_ON) || $this->_lexer->isNextToken(Lexer::T_WITH)) {
|
||||
if ($this->_lexer->isNextToken(Lexer::T_ON)) {
|
||||
$this->match(Lexer::T_ON);
|
||||
$join->setWhereType(AST\Join::JOIN_WHERE_ON);
|
||||
@ -973,6 +972,12 @@ class Parser
|
||||
$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();
|
||||
}
|
||||
|
||||
$this->_lexer->resetPeek();
|
||||
$token = $peek;
|
||||
}
|
||||
@ -1097,6 +1102,52 @@ class Parser
|
||||
return new AST\ArithmeticFactor($this->_ArithmeticPrimary(), $pSign, $nSign);
|
||||
}
|
||||
|
||||
/**
|
||||
* InExpression ::= StateFieldPathExpression ["NOT"] "IN" "(" (Literal {"," Literal}* | Subselect) ")"
|
||||
*/
|
||||
private function _InExpression()
|
||||
{
|
||||
$inExpression = new AST\InExpression($this->_PathExpression());
|
||||
if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
|
||||
$this->match(Lexer::T_NOT);
|
||||
$inExpression->setNot(true);
|
||||
}
|
||||
$this->match(Lexer::T_IN);
|
||||
$this->match('(');
|
||||
if ($this->_lexer->isNextToken(Lexer::T_SELECT)) {
|
||||
$inExpression->setSubselect($this->_Subselect());
|
||||
} else {
|
||||
$literals = array();
|
||||
$literals[] = $this->_Literal();
|
||||
while ($this->_lexer->isNextToken(',')) {
|
||||
$this->match(',');
|
||||
$literals[] = $this->_Literal();
|
||||
}
|
||||
}
|
||||
$this->match(')');
|
||||
|
||||
return $inExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Literal ::= string | char | integer | float | boolean | InputParameter
|
||||
*/
|
||||
private function _Literal()
|
||||
{
|
||||
switch ($this->_lexer->lookahead['type']) {
|
||||
case Lexer::T_INPUT_PARAMETER:
|
||||
$this->match($this->_lexer->lookahead['value']);
|
||||
return new AST\InputParameter($this->_lexer->token['value']);
|
||||
case Lexer::T_STRING:
|
||||
case Lexer::T_INTEGER:
|
||||
case Lexer::T_FLOAT:
|
||||
$this->match($this->_lexer->lookahead['value']);
|
||||
return $this->_lexer->token['value'];
|
||||
default:
|
||||
$this->syntaxError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" | Function | AggregateExpression
|
||||
*/
|
||||
@ -1151,11 +1202,12 @@ class Parser
|
||||
|
||||
break;
|
||||
case 'TRIM':
|
||||
//TODO: This is not complete! See BNF
|
||||
$this->match($this->_lexer->lookahead['value']);
|
||||
$this->match('(');
|
||||
//TODO: This is not complete! See BNF
|
||||
$this->_StringPrimary();
|
||||
break;
|
||||
$func = $this->_StringPrimary();
|
||||
$this->match(')');
|
||||
return $func;
|
||||
case 'LOWER':
|
||||
|
||||
break;
|
||||
|
@ -87,17 +87,17 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
$this->assertValidDql('SELECT COUNT(DISTINCT u.name) FROM Doctrine\Tests\Models\CMS\CmsUser u');
|
||||
}
|
||||
/*
|
||||
|
||||
public function testFunctionalExpressionsSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE TRIM(u.name) = 'someone'");
|
||||
}
|
||||
*/
|
||||
|
||||
public function testArithmeticExpressionsSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000');
|
||||
}
|
||||
/*
|
||||
|
||||
public function testInExpressionSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN (1, 2)');
|
||||
@ -107,8 +107,8 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN (1)');
|
||||
}
|
||||
*/
|
||||
/*public function testExistsExpressionSupportedInWherePart()
|
||||
/*
|
||||
public function testExistsExpressionSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE EXISTS (SELECT p.user_id FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.user_id = u.id)');
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user