1
0
mirror of synced 2024-12-13 06:46:03 +03:00

[2.0] Some more parser work.

This commit is contained in:
romanb 2009-03-14 21:19:50 +00:00
parent c4e22ba87a
commit bc379103c3
5 changed files with 178 additions and 75 deletions

View File

@ -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$
*/

View 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;
}
}

View File

@ -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]

View File

@ -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;

View File

@ -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)');
}