blob: 6ed496bac56a7b91e25f206a6d2f2b400b37d2ba [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: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, KernelEnvironment environment}) {
fileUri ??= uri;
environment ??= new KernelEnvironment(uri, fileUri);
Library library = new Library(uri, fileUri: 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) {
DartType returnType =
node.returnType?.accept<Node, KernelEnvironment>(this, environment);
List<DartType> arguments = <DartType>[];
for (ParsedType argument in node.arguments.required) {
arguments
.add(argument.accept<Node, KernelEnvironment>(this, environment));
}
return new FunctionType(arguments, returnType);
}
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);
}