mirror of https://github.com/AMT-Cheif/drift.git
Parse function expressions
This commit is contained in:
parent
1c75c9d3e8
commit
8bbf6d8054
|
@ -9,6 +9,7 @@ part 'common/queryables.dart';
|
||||||
part 'common/renamable.dart';
|
part 'common/renamable.dart';
|
||||||
|
|
||||||
part 'expressions/expressions.dart';
|
part 'expressions/expressions.dart';
|
||||||
|
part 'expressions/function.dart';
|
||||||
part 'expressions/literals.dart';
|
part 'expressions/literals.dart';
|
||||||
part 'expressions/reference.dart';
|
part 'expressions/reference.dart';
|
||||||
part 'expressions/simple.dart';
|
part 'expressions/simple.dart';
|
||||||
|
@ -41,6 +42,7 @@ abstract class AstVisitor<T> {
|
||||||
T visitIsExpression(IsExpression e);
|
T visitIsExpression(IsExpression e);
|
||||||
T visitLiteral(Literal e);
|
T visitLiteral(Literal e);
|
||||||
T visitReference(Reference e);
|
T visitReference(Reference e);
|
||||||
|
T visitFunction(FunctionExpression e);
|
||||||
|
|
||||||
T visitNumberedVariable(NumberedVariable e);
|
T visitNumberedVariable(NumberedVariable e);
|
||||||
T visitNamedVariable(ColonNamedVariable e);
|
T visitNamedVariable(ColonNamedVariable e);
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
part of '../ast.dart';
|
||||||
|
|
||||||
|
class FunctionExpression extends Expression {
|
||||||
|
final String name;
|
||||||
|
final FunctionParameters parameters;
|
||||||
|
|
||||||
|
FunctionExpression({@required this.name, @required this.parameters});
|
||||||
|
|
||||||
|
@override
|
||||||
|
T accept<T>(AstVisitor<T> visitor) => visitor.visitFunction(this);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<AstNode> get childNodes {
|
||||||
|
return [
|
||||||
|
if (parameters is ExprFunctionParameters)
|
||||||
|
...(parameters as ExprFunctionParameters).parameters
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool contentEquals(FunctionExpression other) {
|
||||||
|
if (other.name != name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters is StarFunctionParameter) {
|
||||||
|
return other.parameters is StarFunctionParameter;
|
||||||
|
} else if (parameters is ExprFunctionParameters) {
|
||||||
|
final typedParams = parameters as ExprFunctionParameters;
|
||||||
|
final typedOther = other.parameters as ExprFunctionParameters;
|
||||||
|
return typedParams.equals(typedOther);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Marker interface for anything that can be inside the parentheses after a
|
||||||
|
/// function name.
|
||||||
|
abstract class FunctionParameters {}
|
||||||
|
|
||||||
|
/// Using a star as a function parameter. For instance: "COUNT(*)".
|
||||||
|
class StarFunctionParameter implements FunctionParameters {
|
||||||
|
const StarFunctionParameter();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExprFunctionParameters implements FunctionParameters {
|
||||||
|
final bool distinct;
|
||||||
|
final List<Expression> parameters;
|
||||||
|
|
||||||
|
ExprFunctionParameters({this.parameters = const [], this.distinct = false});
|
||||||
|
|
||||||
|
bool equals(ExprFunctionParameters other) {
|
||||||
|
return other.distinct == distinct && other.parameters == parameters;
|
||||||
|
}
|
||||||
|
}
|
|
@ -483,13 +483,21 @@ class Parser {
|
||||||
_consume(TokenType.rightParen, 'Expected a closing bracket');
|
_consume(TokenType.rightParen, 'Expected a closing bracket');
|
||||||
return Parentheses(left, expr, _previous);
|
return Parentheses(left, expr, _previous);
|
||||||
case TokenType.identifier:
|
case TokenType.identifier:
|
||||||
|
// could be table.column, function(...) or just column
|
||||||
final first = _previous as IdentifierToken;
|
final first = _previous as IdentifierToken;
|
||||||
if (_match(const [TokenType.dot])) {
|
|
||||||
|
if (_matchOne(TokenType.dot)) {
|
||||||
final second =
|
final second =
|
||||||
_consume(TokenType.identifier, 'Expected a column name here')
|
_consume(TokenType.identifier, 'Expected a column name here')
|
||||||
as IdentifierToken;
|
as IdentifierToken;
|
||||||
return Reference(
|
return Reference(
|
||||||
tableName: first.identifier, columnName: second.identifier);
|
tableName: first.identifier, columnName: second.identifier);
|
||||||
|
} else if (_matchOne(TokenType.leftParen)) {
|
||||||
|
final parameters = _functionParameters();
|
||||||
|
_consume(TokenType.rightParen,
|
||||||
|
'Expected closing bracket after argument list');
|
||||||
|
return FunctionExpression(
|
||||||
|
name: first.identifier, parameters: parameters);
|
||||||
} else {
|
} else {
|
||||||
return Reference(columnName: first.identifier);
|
return Reference(columnName: first.identifier);
|
||||||
}
|
}
|
||||||
|
@ -507,7 +515,6 @@ class Parser {
|
||||||
final identifier = _consume(TokenType.identifier,
|
final identifier = _consume(TokenType.identifier,
|
||||||
'Expected an identifier for the named variable') as IdentifierToken;
|
'Expected an identifier for the named variable') as IdentifierToken;
|
||||||
final content = identifier.identifier;
|
final content = identifier.identifier;
|
||||||
|
|
||||||
return ColonNamedVariable(':$content');
|
return ColonNamedVariable(':$content');
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -516,4 +523,17 @@ class Parser {
|
||||||
// nothing found -> issue error
|
// nothing found -> issue error
|
||||||
_error('Could not parse this expression');
|
_error('Could not parse this expression');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FunctionParameters _functionParameters() {
|
||||||
|
if (_matchOne(TokenType.star)) {
|
||||||
|
return const StarFunctionParameter();
|
||||||
|
}
|
||||||
|
|
||||||
|
final distinct = _matchOne(TokenType.distinct);
|
||||||
|
final parameters = <Expression>[];
|
||||||
|
while (_peek.type != TokenType.rightParen) {
|
||||||
|
parameters.add(expression());
|
||||||
|
}
|
||||||
|
return ExprFunctionParameters(distinct: distinct, parameters: parameters);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import 'utils.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('parses simple expressions', () {
|
test('parses simple expressions', () {
|
||||||
final scanner = Scanner('3 * 4 + 5 == 17');
|
final scanner = Scanner('3 * 4 + 5 == COUNT(*)');
|
||||||
final tokens = scanner.scanTokens();
|
final tokens = scanner.scanTokens();
|
||||||
final parser = Parser(tokens);
|
final parser = Parser(tokens);
|
||||||
|
|
||||||
|
@ -27,7 +27,10 @@ void main() {
|
||||||
NumericLiteral(5, token(TokenType.numberLiteral)),
|
NumericLiteral(5, token(TokenType.numberLiteral)),
|
||||||
),
|
),
|
||||||
token(TokenType.doubleEqual),
|
token(TokenType.doubleEqual),
|
||||||
NumericLiteral(17, token(TokenType.numberLiteral)),
|
FunctionExpression(
|
||||||
|
name: 'COUNT',
|
||||||
|
parameters: const StarFunctionParameter(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue