mirror of
https://github.com/dart-lang/sdk
synced 2024-09-06 00:59:09 +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