blob: ec404ecb5f639c8a22fcdfc89a7b92fda8ea5338 [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import "package:front_end/src/fasta/scanner.dart" show scanString, Token;
import "package:front_end/src/fasta/parser/type_info_impl.dart"
show splitCloser;
abstract class ParsedType {
R accept<R, A>(Visitor<R, A> visitor, [A a]);
}
class ParsedInterfaceType extends ParsedType {
final String name;
final List<ParsedType> arguments;
ParsedInterfaceType(this.name, this.arguments);
String toString() {
StringBuffer sb = new StringBuffer();
sb.write(name);
if (arguments.isNotEmpty) {
sb.write("<");
sb.writeAll(arguments, ", ");
sb.write(">");
}
return "$sb";
}
R accept<R, A>(Visitor<R, A> visitor, [A a]) {
return visitor.visitInterfaceType(this, a);
}
}
abstract class ParsedDeclaration extends ParsedType {
final String name;
ParsedDeclaration(this.name);
}
class ParsedClass extends ParsedDeclaration {
final List<ParsedTypeVariable> typeVariables;
final ParsedInterfaceType supertype;
final List<ParsedType> interfaces;
final ParsedFunctionType callableType;
ParsedClass(String name, this.typeVariables, this.supertype, this.interfaces,
this.callableType)
: super(name);
String toString() {
StringBuffer sb = new StringBuffer();
sb.write("class ");
sb.write(name);
if (typeVariables.isNotEmpty) {
sb.write("<");
sb.writeAll(typeVariables, ", ");
sb.write(">");
}
if (supertype != null) {
sb.write(" extends ");
sb.write(supertype);
}
if (interfaces.isNotEmpty) {
sb.write(" implements ");
sb.writeAll(interfaces, ", ");
}
if (callableType != null) {
sb.write("{\n ");
sb.write(callableType);
sb.write("\n}");
} else {
sb.write(";");
}
return "$sb";
}
R accept<R, A>(Visitor<R, A> visitor, [A a]) {
return visitor.visitClass(this, a);
}
}
class ParsedTypedef extends ParsedDeclaration {
final List<ParsedTypeVariable> typeVariables;
final ParsedType type;
ParsedTypedef(String name, this.typeVariables, this.type) : super(name);
String toString() {
StringBuffer sb = new StringBuffer();
sb.write("typedef ");
sb.write(name);
if (typeVariables.isNotEmpty) {
sb.write("<");
sb.writeAll(typeVariables, ", ");
sb.write(">");
}
sb.write(" ");
sb.write(type);
return "$sb;";
}
R accept<R, A>(Visitor<R, A> visitor, [A a]) {
return visitor.visitTypedef(this, a);
}
}
class ParsedFunctionType extends ParsedType {
final ParsedType returnType;
final ParsedArguments arguments;
ParsedFunctionType(this.returnType, this.arguments);
String toString() {
return "$arguments -> $returnType";
}
R accept<R, A>(Visitor<R, A> visitor, [A a]) {
return visitor.visitFunctionType(this, a);
}
}
class ParsedVoidType extends ParsedType {
String toString() => "void";
R accept<R, A>(Visitor<R, A> visitor, [A a]) {
return visitor.visitVoidType(this, a);
}
}
class ParsedTypeVariable extends ParsedType {
final String name;
final ParsedType bound;
ParsedTypeVariable(this.name, this.bound);
String toString() {
if (bound == null) return name;
StringBuffer sb = new StringBuffer();
sb.write(name);
sb.write(" extends ");
sb.write(bound);
return "$sb";
}
R accept<R, A>(Visitor<R, A> visitor, [A a]) {
return visitor.visitTypeVariable(this, a);
}
}
class ParsedArguments {
final List<ParsedType> required;
final List optional;
final bool optionalAreNamed;
ParsedArguments(this.required, this.optional, this.optionalAreNamed);
String toString() {
StringBuffer sb = new StringBuffer();
sb.write("(");
sb.writeAll(required, ", ");
if (optional.isNotEmpty) {
if (required.isNotEmpty) {
sb.write(", ");
}
if (optionalAreNamed) {
sb.write("{");
for (int i = 0; i < optional.length; i += 2) {
if (i != 0) {
sb.write(", ");
}
sb.write(optional[i]);
sb.write(" ");
sb.write(optional[i + 1]);
}
sb.write("}");
} else {
sb.write("[");
sb.writeAll(optional, ", ");
sb.write("]");
}
}
sb.write(")");
return "$sb";
}
}
class Parser {
Token peek;
String source;
Parser(this.peek, this.source);
bool get atEof => peek.isEof;
void advance() {
peek = peek.next;
}
void expect(String string) {
if (!identical(string, peek.stringValue)) {
String error = "${source.substring(0, peek.charOffset)}\n>>>"
"\n${source.substring(peek.charOffset)}";
throw "Expected `$string`, but got `${peek.lexeme}`\n$error";
}
advance();
}
bool optional(String value) {
return identical(value, peek.stringValue);
}
bool optionalAdvance(String value) {
if (optional(value)) {
advance();
return true;
} else {
return false;
}
}
ParsedType parseType() {
if (optional("class")) return parseClass();
if (optional("typedef")) return parseTypedef();
if (optional("(")) return parseFunctionType();
String name = parseName();
List<ParsedType> arguments = <ParsedType>[];
if (optional("<")) {
advance();
arguments.add(parseType());
while (optional(",")) {
advance();
arguments.add(parseType());
}
peek = splitCloser(peek);
expect(">");
}
return new ParsedInterfaceType(name, arguments);
}
ParsedType parseReturnType() {
if (optionalAdvance("void")) return new ParsedVoidType();
return parseType();
}
ParsedFunctionType parseFunctionType() {
ParsedArguments arguments = parseArguments();
expect("-");
expect(">");
ParsedType returnType = parseReturnType();
return new ParsedFunctionType(returnType, arguments);
}
String parseName() {
if (!peek.isIdentifier) {
throw "Expected a name, but got `${peek.stringValue}`";
}
String result = peek.lexeme;
advance();
return result;
}
ParsedArguments parseArguments() {
List<ParsedType> requiredArguments = <ParsedType>[];
List optionalArguments = [];
bool optionalAreNamed = false;
expect("(");
do {
if (optional(")")) break;
if (optionalAdvance("[")) {
do {
optionalArguments.add(parseType());
} while (optionalAdvance(","));
expect("]");
break;
} else if (optionalAdvance("{")) {
optionalAreNamed = true;
do {
optionalArguments.add(parseType());
optionalArguments.add(parseName());
} while (optionalAdvance(","));
expect("}");
break;
} else {
requiredArguments.add(parseType());
}
} while (optionalAdvance(","));
expect(")");
return new ParsedArguments(
requiredArguments, optionalArguments, optionalAreNamed);
}
List<ParsedTypeVariable> parseTypeVariablesOpt() {
List<ParsedTypeVariable> typeVariables = <ParsedTypeVariable>[];
if (optionalAdvance("<")) {
do {
typeVariables.add(parseTypeVariable());
} while (optionalAdvance(","));
peek = splitCloser(peek);
expect(">");
}
return typeVariables;
}
ParsedTypeVariable parseTypeVariable() {
String name = parseName();
ParsedType bound;
if (optionalAdvance("extends")) {
bound = parseType();
}
return new ParsedTypeVariable(name, bound);
}
ParsedClass parseClass() {
expect("class");
String name = parseName();
List<ParsedTypeVariable> typeVariables = parseTypeVariablesOpt();
ParsedType supertype;
if (optionalAdvance("extends")) {
supertype = parseType();
}
List<ParsedType> interfaces = <ParsedType>[];
if (optionalAdvance("implements")) {
do {
interfaces.add(parseType());
} while (optionalAdvance(","));
}
ParsedFunctionType callableType;
if (optionalAdvance("{")) {
callableType = parseFunctionType();
expect("}");
} else {
expect(";");
}
return new ParsedClass(
name, typeVariables, supertype, interfaces, callableType);
}
/// This parses a general typedef on this form:
///
/// typedef <name> <type-variables-opt> <type> ;
///
/// This is unlike Dart typedef.
ParsedTypedef parseTypedef() {
expect("typedef");
String name = parseName();
List<ParsedTypeVariable> typeVariables = parseTypeVariablesOpt();
ParsedType type = parseType();
expect(";");
return new ParsedTypedef(name, typeVariables, type);
}
}
List<ParsedType> parse(String text) {
Parser parser = new Parser(scanString(text).tokens, text);
List<ParsedType> types = <ParsedType>[];
while (!parser.atEof) {
types.add(parser.parseType());
}
return types;
}
abstract class DefaultAction<R, A> {
R defaultAction(ParsedType node, A a);
static perform<R, A>(Visitor<R, A> visitor, ParsedType node, A a) {
if (visitor is DefaultAction<R, A>) {
DefaultAction<R, A> defaultAction = visitor as DefaultAction<R, A>;
return defaultAction.defaultAction(node, a);
} else {
return null;
}
}
}
abstract class Visitor<R, A> {
R visitInterfaceType(ParsedInterfaceType node, A a) {
return DefaultAction.perform<R, A>(this, node, a);
}
R visitClass(ParsedClass node, A a) {
return DefaultAction.perform<R, A>(this, node, a);
}
R visitTypedef(ParsedTypedef node, A a) {
return DefaultAction.perform<R, A>(this, node, a);
}
R visitFunctionType(ParsedFunctionType node, A a) {
return DefaultAction.perform<R, A>(this, node, a);
}
R visitVoidType(ParsedVoidType node, A a) {
return DefaultAction.perform<R, A>(this, node, a);
}
R visitTypeVariable(ParsedTypeVariable node, A a) {
return DefaultAction.perform<R, A>(this, node, a);
}
}