Create kernel nodes from parsed types
Change-Id: I2f56d05c7d6639ec3e3d7848cddcc665d13086a1
Reviewed-on: https://dart-review.googlesource.com/c/90004
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Peter von der Ahé <ahe@google.com>
diff --git a/pkg/front_end/test/fasta/types/kernel_type_parser.dart b/pkg/front_end/test/fasta/types/kernel_type_parser.dart
new file mode 100644
index 0000000..b535020
--- /dev/null
+++ b/pkg/front_end/test/fasta/types/kernel_type_parser.dart
@@ -0,0 +1,199 @@
+// 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:kernel/ast.dart"
+ show
+ Class,
+ DartType,
+ DynamicType,
+ FunctionType,
+ InterfaceType,
+ Library,
+ Node,
+ Supertype,
+ TreeNode,
+ TypeParameter,
+ TypeParameterType,
+ Typedef,
+ VoidType,
+ setParents;
+
+import "type_parser.dart" as type_parser show parse;
+
+import "type_parser.dart"
+ show
+ ParsedClass,
+ ParsedFunctionType,
+ ParsedInterfaceType,
+ ParsedType,
+ ParsedTypeVariable,
+ ParsedTypedef,
+ ParsedVoidType,
+ Visitor;
+
+Library parseLibrary(Uri uri, String text, {Uri fileUri}) {
+ fileUri ??= uri;
+ Library library = new Library(uri, fileUri: fileUri);
+ KernelEnvironment environment = new KernelEnvironment(uri, fileUri);
+ for (ParsedType type in type_parser.parse(text)) {
+ Node node = environment.kernelFromParsedType(type);
+ if (node is Class) {
+ library.addClass(node);
+ } else {
+ throw "Unsupported: $node";
+ }
+ }
+ return library;
+}
+
+class KernelEnvironment {
+ final Uri uri;
+
+ final Uri fileUri;
+
+ final Map<String, TreeNode> declarations = <String, TreeNode>{};
+
+ KernelEnvironment(this.uri, this.fileUri);
+
+ Node kernelFromParsedType(ParsedType type) {
+ Node node = type.accept(const KernelFromParsedType(), this);
+ return node;
+ }
+
+ bool isObject(String name) => name == "Object" && "$uri" == "dart:core";
+
+ Class get objectClass => this["Object"];
+
+ TreeNode operator [](String name) {
+ return declarations[name] ?? (throw "Not found: $name");
+ }
+
+ void operator []=(String name, TreeNode declaration) {
+ TreeNode existing = declarations[name];
+ if (existing != null) {
+ throw "Duplicated declaration: $name";
+ }
+ declarations[name] = declaration;
+ }
+
+ KernelEnvironment extend(Map<String, TreeNode> declarations) {
+ return new KernelEnvironment(uri, fileUri)
+ ..declarations.addAll(this.declarations)
+ ..declarations.addAll(declarations);
+ }
+}
+
+class KernelFromParsedType implements Visitor<Node, KernelEnvironment> {
+ const KernelFromParsedType();
+
+ DartType visitInterfaceType(
+ ParsedInterfaceType node, KernelEnvironment environment) {
+ TreeNode declaration = environment[node.name];
+ List<ParsedType> arguments = node.arguments;
+ List<DartType> kernelArguments =
+ new List<DartType>.filled(arguments.length, null);
+ for (int i = 0; i < arguments.length; i++) {
+ kernelArguments[i] =
+ arguments[i].accept<Node, KernelEnvironment>(this, environment);
+ }
+ if (declaration is Class) {
+ return new InterfaceType(declaration, kernelArguments);
+ } else if (declaration is TypeParameter) {
+ if (arguments.isNotEmpty) {
+ throw "Type variable can't have arguments (${node.name})";
+ }
+ return new TypeParameterType(declaration);
+ } else {
+ throw "Unhandled ${declaration.runtimeType}";
+ }
+ }
+
+ Class visitClass(ParsedClass node, KernelEnvironment environment) {
+ String name = node.name;
+ Class cls =
+ environment[name] = new Class(fileUri: environment.fileUri, name: name);
+ ParameterEnvironment parameterEnvironment =
+ computeTypeParameterEnvironment(node.typeVariables, environment);
+ List<TypeParameter> parameters = parameterEnvironment.parameters;
+ setParents(parameters, cls);
+ cls.typeParameters.addAll(parameters);
+ {
+ KernelEnvironment environment = parameterEnvironment.environment;
+ InterfaceType type =
+ node.supertype?.accept<Node, KernelEnvironment>(this, environment);
+ if (type == null) {
+ if (!environment.isObject(name)) {
+ cls.supertype = environment.objectClass.asRawSupertype;
+ }
+ } else {
+ cls.supertype = toSupertype(type);
+ }
+ List<ParsedType> interfaces = node.interfaces;
+ for (int i = 0; i < interfaces.length; i++) {
+ cls.implementedTypes.add(toSupertype(
+ interfaces[i].accept<Node, KernelEnvironment>(this, environment)));
+ }
+ }
+ return cls;
+ }
+
+ Typedef visitTypedef(ParsedTypedef node, KernelEnvironment environment) {
+ throw "not implemented: $node";
+ }
+
+ FunctionType visitFunctionType(
+ ParsedFunctionType node, KernelEnvironment environment) {
+ throw "not implemented: $node";
+ }
+
+ VoidType visitVoidType(ParsedVoidType node, KernelEnvironment environment) {
+ return const VoidType();
+ }
+
+ TypeParameter visitTypeVariable(
+ ParsedTypeVariable node, KernelEnvironment environment) {
+ throw "not implemented: $node";
+ }
+
+ Supertype toSupertype(InterfaceType type) {
+ return new Supertype.byReference(type.className, type.typeArguments);
+ }
+
+ ParameterEnvironment computeTypeParameterEnvironment(
+ List<ParsedTypeVariable> typeVariables, KernelEnvironment environment) {
+ List<TypeParameter> typeParameters =
+ new List<TypeParameter>.filled(typeVariables.length, null);
+ Map<String, TypeParameter> typeParametersByName = <String, TypeParameter>{};
+ for (int i = 0; i < typeVariables.length; i++) {
+ String name = typeVariables[i].name;
+ typeParametersByName[name] = typeParameters[i] = new TypeParameter(name);
+ }
+ KernelEnvironment nestedEnvironment =
+ environment.extend(typeParametersByName);
+ for (int i = 0; i < typeVariables.length; i++) {
+ ParsedType bound = typeVariables[i].bound;
+ TypeParameter typeParameter = typeParameters[i];
+ if (bound == null) {
+ typeParameter
+ ..bound = environment.objectClass.rawType
+ ..defaultType = const DynamicType();
+ } else {
+ DartType type =
+ bound.accept<Node, KernelEnvironment>(this, nestedEnvironment);
+ typeParameter
+ ..bound = type
+ ..defaultType = type; // TODO(ahe): Is this correct?
+
+ }
+ }
+ return new ParameterEnvironment(typeParameters, nestedEnvironment);
+ }
+}
+
+class ParameterEnvironment {
+ final List<TypeParameter> parameters;
+ final KernelEnvironment environment;
+
+ const ParameterEnvironment(this.parameters, this.environment);
+}
diff --git a/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart b/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart
new file mode 100644
index 0000000..b348d20
--- /dev/null
+++ b/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart
@@ -0,0 +1,62 @@
+// 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 "package:kernel/ast.dart" show Component, Library;
+
+import "package:kernel/class_hierarchy.dart" show ClassHierarchy;
+
+import "package:kernel/text/ast_to_text.dart" show Printer;
+
+import "kernel_type_parser.dart" show parseLibrary;
+
+const String testSdk = """
+ class Object;
+ class Comparable<T>;
+ class num implements Comparable<num>;
+ class int extends num;
+ class double extends num;
+ class Iterable<T>;
+ class List<T> extends Iterable<T>;
+ class Future<T>;
+ class FutureOr<T>;
+ class Null;
+""";
+
+const String expectedSdk = """
+library;
+import self as self;
+
+class Object {
+}
+class Comparable<T extends self::Object = dynamic> extends self::Object {
+}
+class num extends self::Object implements self::Comparable<self::num> {
+}
+class int extends self::num {
+}
+class double extends self::num {
+}
+class Iterable<T extends self::Object = dynamic> extends self::Object {
+}
+class List<T extends self::Object = dynamic> extends self::Iterable<self::List::T> {
+}
+class Future<T extends self::Object = dynamic> extends self::Object {
+}
+class FutureOr<T extends self::Object = dynamic> extends self::Object {
+}
+class Null extends self::Object {
+}
+""";
+
+main() {
+ Library library = parseLibrary(Uri.parse("dart:core"), testSdk);
+ StringBuffer sb = new StringBuffer();
+ Printer printer = new Printer(sb);
+ printer.writeLibraryFile(library);
+ Expect.stringEquals(expectedSdk, "$sb");
+ Component component = new Component(libraries: <Library>[library]);
+ new ClassHierarchy(component);
+}
diff --git a/pkg/front_end/test/fasta/types/type_parser.dart b/pkg/front_end/test/fasta/types/type_parser.dart
index e7a1901..b1cd825 100644
--- a/pkg/front_end/test/fasta/types/type_parser.dart
+++ b/pkg/front_end/test/fasta/types/type_parser.dart
@@ -4,7 +4,9 @@
import "package:front_end/src/fasta/scanner.dart" show scanString, Token;
-abstract class ParsedType {}
+abstract class ParsedType {
+ R accept<R, A>(Visitor<R, A> visitor, [A a]);
+}
class ParsedInterfaceType extends ParsedType {
final String name;
@@ -23,6 +25,10 @@
}
return "$sb";
}
+
+ R accept<R, A>(Visitor<R, A> visitor, [A a]) {
+ return visitor.visitInterfaceType(this, a);
+ }
}
abstract class ParsedDeclaration extends ParsedType {
@@ -67,6 +73,10 @@
}
return "$sb";
}
+
+ R accept<R, A>(Visitor<R, A> visitor, [A a]) {
+ return visitor.visitClass(this, a);
+ }
}
class ParsedTypedef extends ParsedDeclaration {
@@ -89,6 +99,10 @@
sb.write(type);
return "$sb;";
}
+
+ R accept<R, A>(Visitor<R, A> visitor, [A a]) {
+ return visitor.visitTypedef(this, a);
+ }
}
class ParsedFunctionType extends ParsedType {
@@ -101,10 +115,18 @@
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 {
@@ -115,6 +137,10 @@
ParsedTypeVariable(this.name, this.bound);
String toString() => name;
+
+ R accept<R, A>(Visitor<R, A> visitor, [A a]) {
+ return visitor.visitTypeVariable(this, a);
+ }
}
class ParsedArguments {
@@ -327,3 +353,42 @@
}
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);
+ }
+}