Parse function expressions

This commit is contained in:
Simon Binder 2019-06-23 13:04:05 +02:00
parent 1c75c9d3e8
commit 8bbf6d8054
No known key found for this signature in database
GPG Key ID: 7891917E4147B8C0
4 changed files with 85 additions and 4 deletions

View File

@ -9,6 +9,7 @@ part 'common/queryables.dart';
part 'common/renamable.dart';
part 'expressions/expressions.dart';
part 'expressions/function.dart';
part 'expressions/literals.dart';
part 'expressions/reference.dart';
part 'expressions/simple.dart';
@ -41,6 +42,7 @@ abstract class AstVisitor<T> {
T visitIsExpression(IsExpression e);
T visitLiteral(Literal e);
T visitReference(Reference e);
T visitFunction(FunctionExpression e);
T visitNumberedVariable(NumberedVariable e);
T visitNamedVariable(ColonNamedVariable e);

View File

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

View File

@ -483,13 +483,21 @@ class Parser {
_consume(TokenType.rightParen, 'Expected a closing bracket');
return Parentheses(left, expr, _previous);
case TokenType.identifier:
// could be table.column, function(...) or just column
final first = _previous as IdentifierToken;
if (_match(const [TokenType.dot])) {
if (_matchOne(TokenType.dot)) {
final second =
_consume(TokenType.identifier, 'Expected a column name here')
as IdentifierToken;
return Reference(
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 {
return Reference(columnName: first.identifier);
}
@ -507,7 +515,6 @@ class Parser {
final identifier = _consume(TokenType.identifier,
'Expected an identifier for the named variable') as IdentifierToken;
final content = identifier.identifier;
return ColonNamedVariable(':$content');
default:
break;
@ -516,4 +523,17 @@ class Parser {
// nothing found -> issue error
_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);
}
}

View File

@ -9,7 +9,7 @@ import 'utils.dart';
void main() {
test('parses simple expressions', () {
final scanner = Scanner('3 * 4 + 5 == 17');
final scanner = Scanner('3 * 4 + 5 == COUNT(*)');
final tokens = scanner.scanTokens();
final parser = Parser(tokens);
@ -27,7 +27,10 @@ void main() {
NumericLiteral(5, token(TokenType.numberLiteral)),
),
token(TokenType.doubleEqual),
NumericLiteral(17, token(TokenType.numberLiteral)),
FunctionExpression(
name: 'COUNT',
parameters: const StarFunctionParameter(),
),
),
);
});