Parse ISNULL and NOTNULL postfix expressions

This commit is contained in:
Simon Binder 2020-01-03 17:38:11 +01:00
parent 6924543a47
commit de67ca6e7b
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
7 changed files with 69 additions and 14 deletions

View File

@ -2,7 +2,7 @@
- Added a argument type and argument to the visitor classes
- Experimental new type inference algorithm
- Support `CAST` expressions.
- Support `CAST` expressions and the `ISNULL` / `NOTNULL` postfixes
- Support parsing `CREATE TRIGGER` statements
- Support parsing `CREATE INDEX` statement

View File

@ -115,6 +115,7 @@ class TypeResolver {
} else if (expr is SqlInvocation) {
return resolveFunctionCall(expr);
} else if (expr is IsExpression ||
expr is IsNullExpression ||
expr is InExpression ||
expr is StringComparisonExpression ||
expr is BetweenExpression ||

View File

@ -105,6 +105,28 @@ class IsExpression extends Expression {
}
}
class IsNullExpression extends Expression {
final Expression operand;
/// When true, this is a `NOT NULL` expression.
final bool negated;
IsNullExpression(this.operand, [this.negated = false]);
@override
R accept<A, R>(AstVisitor<A, R> visitor, A arg) {
return visitor.visitIsNullExpression(this, arg);
}
@override
Iterable<AstNode> get childNodes => [operand];
@override
bool contentEquals(IsNullExpression other) {
return other.negated == negated;
}
}
/// `$check BETWEEN $lower AND $upper`
class BetweenExpression extends Expression {
final bool not;

View File

@ -34,6 +34,7 @@ abstract class AstVisitor<A, R> {
R visitStringComparison(StringComparisonExpression e, A arg);
R visitUnaryExpression(UnaryExpression e, A arg);
R visitIsExpression(IsExpression e, A arg);
R visitIsNullExpression(IsNullExpression e, A arg);
R visitBetweenExpression(BetweenExpression e, A arg);
R visitLiteral(Literal e, A arg);
R visitReference(Reference e, A arg);
@ -281,6 +282,11 @@ class RecursiveVisitor<A, R> implements AstVisitor<A, R> {
return visitExpression(e, arg);
}
@override
R visitIsNullExpression(IsNullExpression e, A arg) {
return visitExpression(e, arg);
}
@override
R visitBetweenExpression(BetweenExpression e, A arg) {
return visitExpression(e, arg);

View File

@ -205,21 +205,41 @@ mixin ExpressionParser on ParserBase {
}
Expression _postfix() {
// todo parse ISNULL, NOTNULL, NOT NULL, etc.
// I don't even know the precedence ¯\_(ツ)_/¯ (probably not higher than
// unary)
var expression = _primary();
while (_matchOne(TokenType.collate)) {
final collateOp = _previous;
final collateFun =
_consume(TokenType.identifier, 'Expected a collating sequence')
as IdentifierToken;
expression = CollateExpression(
inner: expression,
operator: collateOp,
collateFunction: collateFun,
)..setSpan(expression.first, collateFun);
// todo we don't currently parse "NOT NULL" (2 tokens) because of ambiguity
// with NOT BETWEEN / NOT IN / ... expressions
const matchedTokens = [
TokenType.collate,
TokenType.notNull,
TokenType.isNull
];
while (_match(matchedTokens)) {
final operator = _previous;
switch (operator.type) {
case TokenType.collate:
final collateOp = _previous;
final collateFun =
_consume(TokenType.identifier, 'Expected a collating sequence')
as IdentifierToken;
expression = CollateExpression(
inner: expression,
operator: collateOp,
collateFunction: collateFun,
);
break;
case TokenType.isNull:
expression = IsNullExpression(expression);
break;
case TokenType.notNull:
expression = IsNullExpression(expression, true);
break;
default:
// we checked with _match, this may never happen
throw AssertionError();
}
expression.setSpan(operator, _previous);
}
return expression;

View File

@ -50,6 +50,8 @@ enum TokenType {
$true,
$false,
$null,
isNull,
notNull,
currentTime,
currentDate,
currentTimestamp,
@ -207,6 +209,8 @@ const Map<String, TokenType> keywords = {
'TRUE': TokenType.$true,
'FALSE': TokenType.$false,
'NULL': TokenType.$null,
'ISNULL': TokenType.isNull,
'NOTNULL': TokenType.notNull,
'CURRENT_TIME': TokenType.currentTime,
'CURRENT_DATE': TokenType.currentDate,
'CURRENT_TIMESTAMP': TokenType.currentTimestamp,

View File

@ -144,6 +144,8 @@ final Map<String, Expression> _testCases = {
),
'TEXT',
),
'foo ISNULL': IsNullExpression(Reference(columnName: 'foo')),
'foo NOTNULL': IsNullExpression(Reference(columnName: 'foo'), true),
};
void main() {