Commit bc379103 authored by romanb's avatar romanb

[2.0] Some more parser work.

parent c4e22ba8
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Query\AST; namespace Doctrine\ORM\Query\AST;
...@@ -26,7 +26,7 @@ namespace Doctrine\ORM\Query\AST; ...@@ -26,7 +26,7 @@ namespace Doctrine\ORM\Query\AST;
* *
* @author Guilherme Blanco <guilhermeblanco@hotmail.com> * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org * @link http://www.doctrine-project.org
* @since 2.0 * @since 2.0
* @version $Revision$ * @version $Revision$
*/ */
......
<?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 @@ ...@@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Query; namespace Doctrine\ORM\Query;
...@@ -28,7 +28,7 @@ namespace Doctrine\ORM\Query; ...@@ -28,7 +28,7 @@ namespace Doctrine\ORM\Query;
* @author Janne Vanhala <jpvanhal@cc.hut.fi> * @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL * @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org * @link www.doctrine-project.org
* @since 2.0 * @since 2.0
* @version $Revision$ * @version $Revision$
*/ */
...@@ -174,7 +174,6 @@ class Lexer ...@@ -174,7 +174,6 @@ class Lexer
if (defined($name)) { if (defined($name)) {
$type = constant($name); $type = constant($name);
if ($type > 100) { if ($type > 100) {
return $type; return $type;
} }
...@@ -319,68 +318,64 @@ class Lexer ...@@ -319,68 +318,64 @@ class Lexer
} }
/** /**
* @todo Doc * Resets the lexer position on the input to the given position.
*/ */
public function resetPosition($position = 0) public function resetPosition($position = 0)
{ {
$this->_position = $position; $this->_position = $position;
} }
private function _addKeyword($token, $value)
{
$this->_keywordsTable[$token] = $value;
}
public function getLiteral($token) public function getLiteral($token)
{ {
if ( ! $this->_keywordsTable) { if ( ! $this->_keywordsTable) {
$this->_addKeyword(self::T_ALL, "ALL"); $this->_keywordsTable = array(
$this->_addKeyword(self::T_AND, "AND"); self::T_ALL => "ALL",
$this->_addKeyword(self::T_ANY, "ANY"); self::T_AND => "AND",
$this->_addKeyword(self::T_AS, "AS"); self::T_ANY => "ANY",
$this->_addKeyword(self::T_ASC, "ASC"); self::T_AS => "AS",
$this->_addKeyword(self::T_AVG, "AVG"); self::T_ASC => "ASC",
$this->_addKeyword(self::T_BETWEEN, "BETWEEN"); self::T_AVG => "AVG",
$this->_addKeyword(self::T_BY, "BY"); self::T_BETWEEN => "BETWEEN",
$this->_addKeyword(self::T_COMMA, ","); self::T_BY => "BY",
$this->_addKeyword(self::T_COUNT, "COUNT"); self::T_COMMA => ",",
$this->_addKeyword(self::T_DELETE, "DELETE"); self::T_COUNT => "COUNT",
$this->_addKeyword(self::T_DESC, "DESC"); self::T_DELETE => "DELETE",
$this->_addKeyword(self::T_DISTINCT, "DISTINCT"); self::T_DESC => "DESC",
$this->_addKeyword(self::T_DOT, "."); self::T_DISTINCT => "DISTINCT",
$this->_addKeyword(self::T_ESCAPE, "ESPACE"); self::T_DOT => ".",
$this->_addKeyword(self::T_EXISTS, "EXISTS"); self::T_ESCAPE => "ESCAPE",
$this->_addKeyword(self::T_FALSE, "FALSE"); self::T_EXISTS => "EXISTS",
$this->_addKeyword(self::T_FROM, "FROM"); self::T_FALSE => "FALSE",
$this->_addKeyword(self::T_GROUP, "GROUP"); self::T_FROM => "FROM",
$this->_addKeyword(self::T_HAVING, "HAVING"); self::T_GROUP => "GROUP",
$this->_addKeyword(self::T_IN, "IN"); self::T_HAVING => "HAVING",
$this->_addKeyword(self::T_INDEX, "INDEX"); self::T_IN => "IN",
$this->_addKeyword(self::T_INNER, "INNER"); self::T_INDEX => "INDEX",
$this->_addKeyword(self::T_IS, "IS"); self::T_INNER => "INNER",
$this->_addKeyword(self::T_JOIN, "JOIN"); self::T_IS => "IS",
$this->_addKeyword(self::T_LEFT, "LEFT"); self::T_JOIN => "JOIN",
$this->_addKeyword(self::T_LIKE, "LIKE"); self::T_LEFT => "LEFT",
$this->_addKeyword(self::T_LIMIT, "LIMIT"); self::T_LIKE => "LIKE",
$this->_addKeyword(self::T_MAX, "MAX"); self::T_LIMIT => "LIMIT",
$this->_addKeyword(self::T_MIN, "MIN"); self::T_MAX => "MAX",
$this->_addKeyword(self::T_MOD, "MOD"); self::T_MIN => "MIN",
$this->_addKeyword(self::T_NOT, "NOT"); self::T_MOD => "MOD",
$this->_addKeyword(self::T_NULL, "NULL"); self::T_NOT => "NOT",
$this->_addKeyword(self::T_OFFSET, "OFFSET"); self::T_NULL => "NULL",
$this->_addKeyword(self::T_ON, "ON"); self::T_OFFSET => "OFFSET",
$this->_addKeyword(self::T_OR, "OR"); self::T_ON => "ON",
$this->_addKeyword(self::T_ORDER, "ORDER"); self::T_OR => "OR",
$this->_addKeyword(self::T_OUTER, "OUTER"); self::T_ORDER => "ORDER",
$this->_addKeyword(self::T_SELECT, "SELECT"); self::T_OUTER => "OUTER",
$this->_addKeyword(self::T_SET, "SET"); self::T_SELECT => "SELECT",
$this->_addKeyword(self::T_SIZE, "SIZE"); self::T_SET => "SET",
$this->_addKeyword(self::T_SOME, "SOME"); self::T_SIZE => "SIZE",
$this->_addKeyword(self::T_SUM, "SUM"); self::T_SOME => "SOME",
$this->_addKeyword(self::T_TRUE, "TRUE"); self::T_SUM => "SUM",
$this->_addKeyword(self::T_UPDATE, "UPDATE"); self::T_TRUE => "TRUE",
$this->_addKeyword(self::T_WHERE, "WHERE"); self::T_UPDATE => "UPDATE",
$this->_addKeyword(self::T_WITH, "WITH"); self::T_WHERE => "WHERE",
self::T_WITH => "WITH");
} }
return isset($this->_keywordsTable[$token]) return isset($this->_keywordsTable[$token])
? $this->_keywordsTable[$token] ? $this->_keywordsTable[$token]
......
...@@ -319,8 +319,6 @@ class Parser ...@@ -319,8 +319,6 @@ class Parser
/** /**
* QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement * QueryLanguage ::= SelectStatement | UpdateStatement | DeleteStatement
*
* @return <type>
*/ */
private function _QueryLanguage() private function _QueryLanguage()
{ {
...@@ -346,8 +344,6 @@ class Parser ...@@ -346,8 +344,6 @@ class Parser
/** /**
* SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] * SelectStatement ::= SelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause]
*
* @return <type>
*/ */
private function _SelectStatement() private function _SelectStatement()
{ {
...@@ -427,11 +423,17 @@ class Parser ...@@ -427,11 +423,17 @@ class Parser
} }
} }
/**
* UpdateStatement ::= UpdateClause [WhereClause]
*/
private function _UpdateStatement() private function _UpdateStatement()
{ {
//TODO //TODO
} }
/**
* DeleteStatement ::= DeleteClause [WhereClause]
*/
private function _DeleteStatement() private function _DeleteStatement()
{ {
//TODO //TODO
...@@ -496,7 +498,7 @@ class Parser ...@@ -496,7 +498,7 @@ class Parser
if ($this->_lexer->isNextToken(Lexer::T_AS)) { if ($this->_lexer->isNextToken(Lexer::T_AS)) {
$this->match(Lexer::T_AS); $this->match(Lexer::T_AS);
$fieldIdentificationVariable = $this->_FieldAliasIdentificationVariable(); $fieldIdentificationVariable = $this->_FieldAliasIdentificationVariable();
} elseif ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) { } else if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
$fieldIdentificationVariable = $this->_FieldAliasIdentificationVariable(); $fieldIdentificationVariable = $this->_FieldAliasIdentificationVariable();
} }
} else { } else {
...@@ -677,10 +679,7 @@ class Parser ...@@ -677,10 +679,7 @@ class Parser
$join = new AST\Join($joinType, $joinPathExpression, $aliasIdentificationVariable); $join = new AST\Join($joinType, $joinPathExpression, $aliasIdentificationVariable);
// Check Join where type // Check Join where type
if ( if ($this->_lexer->isNextToken(Lexer::T_ON) || $this->_lexer->isNextToken(Lexer::T_WITH)) {
$this->_lexer->isNextToken(Lexer::T_ON) ||
$this->_lexer->isNextToken(Lexer::T_WITH)
) {
if ($this->_lexer->isNextToken(Lexer::T_ON)) { if ($this->_lexer->isNextToken(Lexer::T_ON)) {
$this->match(Lexer::T_ON); $this->match(Lexer::T_ON);
$join->setWhereType(AST\Join::JOIN_WHERE_ON); $join->setWhereType(AST\Join::JOIN_WHERE_ON);
...@@ -973,6 +972,12 @@ class Parser ...@@ -973,6 +972,12 @@ class Parser
$this->_lexer->peek(); $this->_lexer->peek();
$peek = $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(); $this->_lexer->resetPeek();
$token = $peek; $token = $peek;
} }
...@@ -1097,6 +1102,52 @@ class Parser ...@@ -1097,6 +1102,52 @@ class Parser
return new AST\ArithmeticFactor($this->_ArithmeticPrimary(), $pSign, $nSign); 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 * ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" | Function | AggregateExpression
*/ */
...@@ -1151,11 +1202,12 @@ class Parser ...@@ -1151,11 +1202,12 @@ class Parser
break; break;
case 'TRIM': case 'TRIM':
//TODO: This is not complete! See BNF
$this->match($this->_lexer->lookahead['value']); $this->match($this->_lexer->lookahead['value']);
$this->match('('); $this->match('(');
//TODO: This is not complete! See BNF $func = $this->_StringPrimary();
$this->_StringPrimary(); $this->match(')');
break; return $func;
case 'LOWER': case 'LOWER':
break; break;
......
...@@ -87,17 +87,17 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase ...@@ -87,17 +87,17 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
{ {
$this->assertValidDql('SELECT COUNT(DISTINCT u.name) FROM Doctrine\Tests\Models\CMS\CmsUser u'); $this->assertValidDql('SELECT COUNT(DISTINCT u.name) FROM Doctrine\Tests\Models\CMS\CmsUser u');
} }
/*
public function testFunctionalExpressionsSupportedInWherePart() public function testFunctionalExpressionsSupportedInWherePart()
{ {
$this->assertValidDql("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE TRIM(u.name) = 'someone'"); $this->assertValidDql("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE TRIM(u.name) = 'someone'");
} }
*/
public function testArithmeticExpressionsSupportedInWherePart() public function testArithmeticExpressionsSupportedInWherePart()
{ {
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000'); $this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE ((u.id + 5000) * u.id + 3) < 10000000');
} }
/*
public function testInExpressionSupportedInWherePart() public function testInExpressionSupportedInWherePart()
{ {
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN (1, 2)'); $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 ...@@ -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)'); $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)'); $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)');
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment