mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 15:42:20 +00:00
Restore type parser from reify project
Change-Id: Ic347890a4146cadb3ad1b6049b562350903505e7 Reviewed-on: https://dart-review.googlesource.com/c/89660 Reviewed-by: Dmitry Stefantsov <dmitryas@google.com> Commit-Queue: Peter von der Ahé <ahe@google.com>
This commit is contained in:
parent
65dde13f1b
commit
8b214f4d72
329
pkg/front_end/test/fasta/types/type_parser.dart
Normal file
329
pkg/front_end/test/fasta/types/type_parser.dart
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
abstract class ParsedType {}
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParsedFunctionType extends ParsedType {
|
||||||
|
final ParsedType returnType;
|
||||||
|
|
||||||
|
final ParsedArguments arguments;
|
||||||
|
|
||||||
|
ParsedFunctionType(this.returnType, this.arguments);
|
||||||
|
|
||||||
|
String toString() {
|
||||||
|
return "$arguments -> $returnType";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParsedVoidType extends ParsedType {
|
||||||
|
String toString() => "void";
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParsedTypeVariable extends ParsedType {
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
final ParsedType bound;
|
||||||
|
|
||||||
|
ParsedTypeVariable(this.name, this.bound);
|
||||||
|
|
||||||
|
String toString() => name;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
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(","));
|
||||||
|
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;
|
||||||
|
}
|
37
pkg/front_end/test/fasta/types/type_parser_test.dart
Normal file
37
pkg/front_end/test/fasta/types/type_parser_test.dart
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
// 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:expect/expect.dart" show Expect;
|
||||||
|
|
||||||
|
import "type_parser.dart";
|
||||||
|
|
||||||
|
testParse(String text) {
|
||||||
|
Expect.stringEquals(text.trim(), "${parse(text).join('\n')}");
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
testParse("""
|
||||||
|
() -> void
|
||||||
|
(int) -> dynamic
|
||||||
|
([int]) -> int
|
||||||
|
({double parameter}) -> int
|
||||||
|
(num, [int]) -> int
|
||||||
|
(num, {double parameter}) -> int
|
||||||
|
class Object;
|
||||||
|
class Comparable<T>;
|
||||||
|
class num implements Comparable<num>;
|
||||||
|
class int extends num;
|
||||||
|
class double extends num;
|
||||||
|
class Function;
|
||||||
|
class Iterable<E>;
|
||||||
|
class EfficientLength;
|
||||||
|
class List<E> implements Iterable<E>, EfficientLength;
|
||||||
|
class Intersection implements Comparable<int>, Comparable<double>;
|
||||||
|
typedef OtherObject Object;
|
||||||
|
typedef MyList<T> List<T>;
|
||||||
|
typedef StringList List<String>;
|
||||||
|
typedef VoidFunction () -> void;
|
||||||
|
typedef GenericFunction<T> () -> T;
|
||||||
|
""");
|
||||||
|
}
|
Loading…
Reference in a new issue