Parse exists expressions

This commit is contained in:
Simon Binder 2019-07-01 14:23:37 +02:00
parent 3e910123d2
commit da07be2da4
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
7 changed files with 44 additions and 6 deletions

View File

@ -78,7 +78,10 @@ class TypeResolver {
return resolveColumn(expr.resolved as Column);
} else if (expr is FunctionExpression) {
return resolveFunctionCall(expr);
} else if (expr is IsExpression) {
} else if (expr is IsExpression ||
expr is StringComparisonExpression ||
expr is BetweenExpression ||
expr is ExistsExpression) {
return const ResolveResult(ResolvedType.bool());
} else if (expr is BinaryExpression) {
final operator = expr.operator.type;
@ -89,10 +92,6 @@ class TypeResolver {
[BasicType.int, BasicType.real, BasicType.text, BasicType.blob]);
return ResolveResult(type);
}
} else if (expr is StringComparisonExpression) {
return const ResolveResult(ResolvedType.bool());
} else if (expr is BetweenExpression) {
return const ResolveResult(ResolvedType.bool());
} else if (expr is CaseExpression) {
return resolveExpression(expr.whens.first.then);
} else if (expr is SubQuery) {

View File

@ -145,6 +145,7 @@ abstract class AstVisitor<T> {
T visitReference(Reference e);
T visitFunction(FunctionExpression e);
T visitSubQuery(SubQuery e);
T visitExists(ExistsExpression e);
T visitCaseExpression(CaseExpression e);
T visitWhen(WhenComponent e);
@ -181,6 +182,9 @@ class RecursiveVisitor<T> extends AstVisitor<T> {
@override
T visitSubQuery(SubQuery e) => visitChildren(e);
@override
T visitExists(ExistsExpression e) => visitChildren(e);
@override
T visitSetComponent(SetComponent e) => visitChildren(e);

View File

@ -16,3 +16,18 @@ class SubQuery extends Expression {
@override
bool contentEquals(SubQuery other) => true;
}
class ExistsExpression extends Expression {
final SelectStatement select;
ExistsExpression({@required this.select});
@override
T accept<T>(AstVisitor<T> visitor) => visitor.visitExists(this);
@override
Iterable<AstNode> get childNodes => [select];
@override
bool contentEquals(ExistsExpression other) => true;
}

View File

@ -33,9 +33,9 @@ class SelectStatement extends Statement with ResultSet {
@override
Iterable<AstNode> get childNodes {
return [
if (where != null) where,
...columns,
if (from != null) ...from,
if (where != null) where,
if (groupBy != null) groupBy,
if (limit != null) limit,
if (orderBy != null) orderBy,

View File

@ -612,6 +612,13 @@ class Parser {
final operator = _previous;
final expression = _unary();
return UnaryExpression(operator, expression);
} else if (_matchOne(TokenType.exists)) {
_consume(
TokenType.leftParen, 'Expected opening parenthesis after EXISTS');
final selectStmt = select();
_consume(TokenType.rightParen,
'Expected closing paranthesis to finish EXISTS expression');
return ExistsExpression(select: selectStmt);
}
return _postfix();

View File

@ -35,6 +35,7 @@ enum TokenType {
or,
tilde,
between,
exists,
questionMark,
colon,
@ -104,6 +105,7 @@ const Map<String, TokenType> keywords = {
'ALL': TokenType.all,
'AND': TokenType.and,
'OR': TokenType.or,
'EXISTS': TokenType.exists,
'BETWEEN': TokenType.between,
'DELETE': TokenType.delete,
'FROM': TokenType.from,

View File

@ -72,6 +72,17 @@ final Map<String, Expression> _testCases = {
right: StringLiteral.from(token(TokenType.stringLiteral), '%A%\$'),
escape: StringLiteral.from(token(TokenType.stringLiteral), '\$'),
),
'NOT EXISTS (SELECT * FROM demo)': UnaryExpression(
token(TokenType.not),
ExistsExpression(
select: SelectStatement(
columns: [StarResultColumn(null)],
from: [
TableReference('demo', null),
],
),
),
),
};
void main() {