blob: 22be183cc9045b5c00797c7193386b0b47028778 [file] [log] [blame]
// Copyright (c) 2016, 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.
library fasta.kernel_library_builder;
import 'package:kernel/ast.dart';
import 'package:kernel/clone.dart' show CloneVisitor;
import '../errors.dart' show internalError;
import '../loader.dart' show Loader;
import '../modifier.dart' show abstractMask, staticMask;
import '../source/source_library_builder.dart'
show DeclarationBuilder, SourceLibraryBuilder;
import '../source/source_class_builder.dart' show SourceClassBuilder;
import '../util/relativize.dart' show relativizeUri;
import 'kernel_builder.dart'
show
Builder,
ClassBuilder,
ConstructorReferenceBuilder,
DynamicTypeBuilder,
FormalParameterBuilder,
FunctionTypeAliasBuilder,
KernelConstructorBuilder,
KernelEnumBuilder,
KernelFieldBuilder,
KernelFormalParameterBuilder,
KernelFunctionTypeAliasBuilder,
KernelInvalidTypeBuilder,
KernelMixinApplicationBuilder,
KernelNamedMixinApplicationBuilder,
KernelNamedTypeBuilder,
KernelProcedureBuilder,
KernelTypeBuilder,
KernelTypeVariableBuilder,
MemberBuilder,
MetadataBuilder,
MixedAccessor,
NamedMixinApplicationBuilder,
PrefixBuilder,
ProcedureBuilder,
TypeBuilder,
TypeVariableBuilder;
class KernelLibraryBuilder
extends SourceLibraryBuilder<KernelTypeBuilder, Library> {
final Library library;
final Map<String, SourceClassBuilder> mixinApplicationClasses =
<String, SourceClassBuilder>{};
final List<List> argumentsWithMissingDefaultValues = <List>[];
final List<KernelProcedureBuilder> nativeMethods = <KernelProcedureBuilder>[];
final List<KernelTypeVariableBuilder> boundlessTypeVariables =
<KernelTypeVariableBuilder>[];
KernelLibraryBuilder(Uri uri, Uri fileUri, Loader loader)
: library = new Library(uri, fileUri: relativizeUri(fileUri)),
super(loader, fileUri);
Uri get uri => library.importUri;
KernelTypeBuilder addNamedType(
String name, List<KernelTypeBuilder> arguments, int charOffset) {
KernelNamedTypeBuilder type =
new KernelNamedTypeBuilder(name, arguments, charOffset, fileUri);
if (identical(name, "dynamic")) {
type.builder =
new DynamicTypeBuilder(const DynamicType(), this, charOffset);
} else {
addType(type);
}
return type;
}
KernelTypeBuilder addMixinApplication(KernelTypeBuilder supertype,
List<KernelTypeBuilder> mixins, int charOffset) {
KernelTypeBuilder type = new KernelMixinApplicationBuilder(
supertype, mixins, this, charOffset, fileUri);
return addType(type);
}
KernelTypeBuilder addVoidType(int charOffset) {
return new KernelNamedTypeBuilder("void", null, charOffset, fileUri);
}
void addClass(
List<MetadataBuilder> metadata,
int modifiers,
String className,
List<TypeVariableBuilder> typeVariables,
KernelTypeBuilder supertype,
List<KernelTypeBuilder> interfaces,
int charOffset) {
ClassBuilder cls = new SourceClassBuilder(
metadata,
modifiers,
className,
typeVariables,
supertype,
interfaces,
classMembers,
this,
new List<ConstructorReferenceBuilder>.from(constructorReferences),
charOffset);
constructorReferences.clear();
classMembers.forEach((String name, MemberBuilder builder) {
while (builder != null) {
builder.parent = cls;
builder = builder.next;
}
});
// Nested declaration began in `OutlineBuilder.beginClassDeclaration`.
endNestedDeclaration().resolveTypes(typeVariables, this);
addBuilder(className, cls, charOffset);
}
void addNamedMixinApplication(
List<MetadataBuilder> metadata,
String name,
List<TypeVariableBuilder> typeVariables,
int modifiers,
KernelTypeBuilder mixinApplication,
List<KernelTypeBuilder> interfaces,
int charOffset) {
NamedMixinApplicationBuilder builder =
new KernelNamedMixinApplicationBuilder(metadata, name, typeVariables,
modifiers, mixinApplication, interfaces, this, charOffset);
// Nested declaration began in `OutlineBuilder.beginNamedMixinApplication`.
endNestedDeclaration().resolveTypes(typeVariables, this);
addBuilder(name, builder, charOffset);
}
void addField(List<MetadataBuilder> metadata, int modifiers,
KernelTypeBuilder type, String name, int charOffset) {
addBuilder(
name,
new KernelFieldBuilder(
metadata, type, name, modifiers, this, charOffset),
charOffset);
}
void addProcedure(
List<MetadataBuilder> metadata,
int modifiers,
KernelTypeBuilder returnType,
String name,
List<TypeVariableBuilder> typeVariables,
List<FormalParameterBuilder> formals,
AsyncMarker asyncModifier,
ProcedureKind kind,
int charOffset,
String nativeMethodName,
{bool isTopLevel}) {
// Nested declaration began in `OutlineBuilder.beginMethod` or
// `OutlineBuilder.beginTopLevelMethod`.
endNestedDeclaration().resolveTypes(typeVariables, this);
ProcedureBuilder procedure;
if (!isTopLevel && isConstructorName(name, currentDeclaration.name)) {
int index = name.indexOf(".");
name = index == -1 ? "" : name.substring(index + 1);
procedure = new KernelConstructorBuilder(
metadata,
modifiers & ~abstractMask,
returnType,
name,
typeVariables,
formals,
this,
charOffset,
nativeMethodName);
} else {
procedure = new KernelProcedureBuilder(
metadata,
modifiers,
returnType,
name,
typeVariables,
formals,
asyncModifier,
kind,
this,
charOffset,
nativeMethodName);
}
addBuilder(name, procedure, charOffset);
if (nativeMethodName != null) {
addNativeMethod(procedure);
}
}
void addFactoryMethod(
List<MetadataBuilder> metadata,
ConstructorReferenceBuilder constructorName,
List<FormalParameterBuilder> formals,
AsyncMarker asyncModifier,
ConstructorReferenceBuilder redirectionTarget,
int charOffset,
String nativeMethodName) {
// Nested declaration began in `OutlineBuilder.beginFactoryMethod`.
DeclarationBuilder<KernelTypeBuilder> factoryDeclaration =
endNestedDeclaration();
String name = constructorName.name;
int index = name.indexOf(".");
name = index == -1 ? "" : name.substring(index + 1);
assert(constructorName.suffix == null);
KernelProcedureBuilder procedure = new KernelProcedureBuilder(
metadata,
staticMask,
null,
name,
<TypeVariableBuilder>[],
formals,
asyncModifier,
ProcedureKind.Factory,
this,
charOffset,
nativeMethodName,
redirectionTarget);
currentDeclaration.addFactoryDeclaration(procedure, factoryDeclaration);
addBuilder(name, procedure, charOffset);
if (nativeMethodName != null) {
addNativeMethod(procedure);
}
}
void addEnum(List<MetadataBuilder> metadata, String name,
List<String> constants, int charOffset) {
addBuilder(
name,
new KernelEnumBuilder(metadata, name, constants, this, charOffset),
charOffset);
}
void addFunctionTypeAlias(
List<MetadataBuilder> metadata,
KernelTypeBuilder returnType,
String name,
List<TypeVariableBuilder> typeVariables,
List<FormalParameterBuilder> formals,
int charOffset) {
FunctionTypeAliasBuilder typedef = new KernelFunctionTypeAliasBuilder(
metadata, returnType, name, typeVariables, formals, this, charOffset);
// Nested declaration began in `OutlineBuilder.beginFunctionTypeAlias`.
endNestedDeclaration().resolveTypes(typeVariables, this);
addBuilder(name, typedef, charOffset);
}
KernelFormalParameterBuilder addFormalParameter(
List<MetadataBuilder> metadata,
int modifiers,
KernelTypeBuilder type,
String name,
bool hasThis,
int charOffset) {
return new KernelFormalParameterBuilder(
metadata, modifiers, type, name, hasThis, this, charOffset);
}
KernelTypeVariableBuilder addTypeVariable(
String name, KernelTypeBuilder bound, int charOffset) {
var builder = new KernelTypeVariableBuilder(name, this, charOffset, bound);
boundlessTypeVariables.add(builder);
return builder;
}
void buildBuilder(Builder builder) {
if (builder is SourceClassBuilder) {
Class cls = builder.build(this);
library.addClass(cls);
} else if (builder is KernelFieldBuilder) {
library.addMember(builder.build(library)..isStatic = true);
} else if (builder is KernelProcedureBuilder) {
library.addMember(builder.build(library)..isStatic = true);
} else if (builder is FunctionTypeAliasBuilder) {
// Kernel discard typedefs and use their corresponding function types
// directly.
} else if (builder is KernelEnumBuilder) {
library.addClass(builder.build(this));
} else if (builder is PrefixBuilder) {
// Ignored. Kernel doesn't represent prefixes.
} else {
internalError("Unhandled builder: ${builder.runtimeType}");
}
}
Library build() {
super.build();
library.name = name;
return library;
}
Builder buildAmbiguousBuilder(
String name, Builder builder, Builder other, int charOffset) {
if (builder.next == null && other.next == null) {
if (builder.isGetter && other.isSetter) {
return new MixedAccessor(builder, other, this);
} else if (builder.isSetter && other.isGetter) {
return new MixedAccessor(other, builder, this);
}
}
return new KernelInvalidTypeBuilder(name, charOffset, fileUri);
}
void addArgumentsWithMissingDefaultValues(
Arguments arguments, FunctionNode function) {
assert(partOfLibrary == null);
argumentsWithMissingDefaultValues.add([arguments, function]);
}
int finishStaticInvocations() {
CloneVisitor cloner;
for (var list in argumentsWithMissingDefaultValues) {
final Arguments arguments = list[0];
final FunctionNode function = list[1];
Expression defaultArgumentFrom(Expression expression) {
if (expression == null) {
return new NullLiteral();
}
cloner ??= new CloneVisitor();
return cloner.clone(expression);
}
for (int i = function.requiredParameterCount;
i < function.positionalParameters.length;
i++) {
arguments.positional[i] ??=
defaultArgumentFrom(function.positionalParameters[i].initializer)
..parent = arguments;
}
Map<String, VariableDeclaration> names;
for (NamedExpression expression in arguments.named) {
if (expression.value == null) {
if (names == null) {
names = <String, VariableDeclaration>{};
for (VariableDeclaration parameter in function.namedParameters) {
names[parameter.name] = parameter;
}
}
expression.value =
defaultArgumentFrom(names[expression.name].initializer)
..parent = expression;
}
}
}
return argumentsWithMissingDefaultValues.length;
}
void addNativeMethod(KernelProcedureBuilder method) {
nativeMethods.add(method);
}
int finishNativeMethods() {
for (KernelProcedureBuilder method in nativeMethods) {
method.becomeNative(loader);
}
return nativeMethods.length;
}
List<TypeVariableBuilder> copyTypeVariables(
List<TypeVariableBuilder> original) {
List<TypeVariableBuilder> copy = <TypeVariableBuilder>[];
for (KernelTypeVariableBuilder variable in original) {
var newVariable = new KernelTypeVariableBuilder(
variable.name, this, variable.charOffset);
copy.add(newVariable);
boundlessTypeVariables.add(newVariable);
}
Map<TypeVariableBuilder, TypeBuilder> substitution =
<TypeVariableBuilder, TypeBuilder>{};
int i = 0;
for (KernelTypeVariableBuilder variable in original) {
substitution[variable] = copy[i++].asTypeBuilder();
}
i = 0;
for (KernelTypeVariableBuilder variable in original) {
copy[i++].bound = variable.bound?.subst(substitution);
}
return copy;
}
int finishTypeVariables(ClassBuilder object) {
int count = boundlessTypeVariables.length;
for (KernelTypeVariableBuilder builder in boundlessTypeVariables) {
builder.finish(object);
}
boundlessTypeVariables.clear();
return count;
}
@override
void includePart(covariant KernelLibraryBuilder part) {
super.includePart(part);
nativeMethods.addAll(part.nativeMethods);
boundlessTypeVariables.addAll(part.boundlessTypeVariables);
assert(mixinApplicationClasses.isEmpty);
}
}
bool isConstructorName(String name, String className) {
if (name.startsWith(className)) {
if (name.length == className.length) return true;
if (name.startsWith(".", className.length)) return true;
}
return false;
}