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);
+  }
+}