blob: a62164442ec1fd1f4910c84003938e2fadd47c79 [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 entities;
import 'package:front_end/src/api_unstable/dart2js.dart' show AsyncModifier;
import '../common.dart';
import '../serialization/serialization.dart';
import '../universe/call_structure.dart' show CallStructure;
import '../util/util.dart';
import 'names.dart';
import 'types.dart';
/// Abstract interface for entities.
///
/// Implement this directly if the entity is not a Dart language entity.
/// Entities defined within the Dart language should implement [Element].
///
/// For instance, the JavaScript backend need to create synthetic variables for
/// calling intercepted classes and such variables do not correspond to an
/// entity in the Dart source code nor in the terminology of the Dart language
/// and should therefore implement [Entity] directly.
abstract class Entity implements Spannable {
String get name;
}
/// Stripped down super interface for library like entities.
///
/// Currently only [LibraryElement] but later also kernel based Dart classes
/// and/or Dart-in-JS classes.
abstract class LibraryEntity extends Entity {
/// Return the canonical uri that identifies this library.
Uri get canonicalUri;
}
/// Stripped down super interface for import entities.
///
/// The [name] property corresponds to the prefix name, if any.
class ImportEntity {
final String name;
/// The canonical URI of the library where this import occurs
/// (where the import is declared).
final Uri enclosingLibraryUri;
/// Whether the import is a deferred import.
final bool isDeferred;
/// The target import URI.
final Uri uri;
ImportEntity(this.isDeferred, this.name, this.uri, this.enclosingLibraryUri);
@override
String toString() => 'import($name:${isDeferred ? ' deferred' : ''})';
}
/// Stripped down super interface for class like entities.
///
/// Currently only [ClassElement] but later also kernel based Dart classes
/// and/or Dart-in-JS classes.
abstract class ClassEntity extends Entity {
/// If this is a normal class, the enclosing library for this class. If this
/// is a closure class, the enclosing class of the closure for which it was
/// created.
LibraryEntity get library;
/// Whether this is a synthesized class for a closurized method or local
/// function.
bool get isClosure;
/// Whether this is an abstract class.
bool get isAbstract;
}
abstract class TypedefEntity extends Entity {
/// The library in which the typedef was declared.
LibraryEntity get library;
}
abstract class TypeVariableEntity extends Entity {
/// The class or generic method that declared this type variable.
Entity get typeDeclaration;
/// The index of this type variable in the type variables of its
/// [typeDeclaration].
int get index;
}
/// Stripped down super interface for member like entities, that is,
/// constructors, methods, fields etc.
///
/// Currently only [MemberElement] but later also kernel based Dart members
/// and/or Dart-in-JS properties.
abstract class MemberEntity extends Entity {
/// The [Name] of member which takes privacy and getter/setter naming into
/// account.
Name get memberName;
/// Whether this is a member of a library.
bool get isTopLevel;
/// Whether this is a static member of a class.
bool get isStatic;
/// Whether this is an instance member of a class.
bool get isInstanceMember;
/// Whether this is a constructor.
bool get isConstructor;
/// Whether this is a field.
bool get isField;
/// Whether this is a normal method (neither constructor, getter or setter)
/// or operator method.
bool get isFunction;
/// Whether this is a getter.
bool get isGetter;
/// Whether this is a setter.
bool get isSetter;
/// Whether this member is assignable, i.e. a non-final, non-const field.
bool get isAssignable;
/// Whether this member is constant, i.e. a constant field or constructor.
bool get isConst;
/// Whether this member is abstract, i.e. an abstract method, getter or
/// setter.
bool get isAbstract;
/// The enclosing class if this is a constructor, instance member or
/// static member of a class.
ClassEntity get enclosingClass;
/// The enclosing library if this is a library member, otherwise the
/// enclosing library of the [enclosingClass].
LibraryEntity get library;
}
/// Stripped down super interface for field like entities.
///
/// Currently only [FieldElement] but later also kernel based Dart fields
/// and/or Dart-in-JS field-like properties.
abstract class FieldEntity extends MemberEntity {}
/// Stripped down super interface for function like entities.
///
/// Currently only [MethodElement] but later also kernel based Dart constructors
/// and methods and/or Dart-in-JS function-like properties.
abstract class FunctionEntity extends MemberEntity {
/// Whether this function is external, i.e. the body is not defined in terms
/// of Dart code.
bool get isExternal;
/// The structure of the function parameters.
ParameterStructure get parameterStructure;
/// The synchronous/asynchronous marker on this function.
AsyncMarker get asyncMarker;
}
/// Enum for the synchronous/asynchronous function body modifiers.
class AsyncMarker {
/// The default function body marker.
static const AsyncMarker SYNC = const AsyncMarker._(AsyncModifier.Sync);
/// The `sync*` function body marker.
static const AsyncMarker SYNC_STAR =
const AsyncMarker._(AsyncModifier.SyncStar, isYielding: true);
/// The `async` function body marker.
static const AsyncMarker ASYNC =
const AsyncMarker._(AsyncModifier.Async, isAsync: true);
/// The `async*` function body marker.
static const AsyncMarker ASYNC_STAR = const AsyncMarker._(
AsyncModifier.AsyncStar,
isAsync: true,
isYielding: true);
/// Is `true` if this marker defines the function body to have an
/// asynchronous result, that is, either a [Future] or a [Stream].
final bool isAsync;
/// Is `true` if this marker defines the function body to have a plural
/// result, that is, either an [Iterable] or a [Stream].
final bool isYielding;
final AsyncModifier asyncParserState;
const AsyncMarker._(this.asyncParserState,
{this.isAsync: false, this.isYielding: false});
@override
String toString() {
return '${isAsync ? 'async' : 'sync'}${isYielding ? '*' : ''}';
}
/// Canonical list of marker values.
///
/// Added to make [AsyncMarker] enum-like.
static const List<AsyncMarker> values = const <AsyncMarker>[
SYNC,
SYNC_STAR,
ASYNC,
ASYNC_STAR
];
/// Index to this marker within [values].
///
/// Added to make [AsyncMarker] enum-like.
int get index => values.indexOf(this);
}
/// Stripped down super interface for constructor like entities.
///
/// Currently only [ConstructorElement] but later also kernel based Dart
/// constructors and/or Dart-in-JS constructor-like properties.
// TODO(johnniwinther): Remove factory constructors from the set of
// constructors.
abstract class ConstructorEntity extends FunctionEntity {
/// Whether this is a generative constructor, possibly redirecting.
bool get isGenerativeConstructor;
/// Whether this is a factory constructor, possibly redirecting.
bool get isFactoryConstructor;
/// Whether this is a `fromEnvironment` const constructor in `int`, `bool` or
/// `String`.
bool get isFromEnvironmentConstructor;
}
/// The constructor body for a [ConstructorEntity].
///
/// This is used only in the backend to split encoding of a Dart constructor
/// into two JavaScript functions; the constructor and the constructor body.
// TODO(johnniwinther): Remove this when modelx is removed. Constructor bodies
// should then be created directly with the J-model.
abstract class ConstructorBodyEntity extends FunctionEntity {
/// The constructor for which this constructor body was created.
ConstructorEntity get constructor;
}
/// An entity that defines a local entity (memory slot) in generated code.
///
/// Parameters, local variables and local functions (can) define local entity
/// and thus implement [Local] through [LocalElement]. For non-element locals,
/// like `this` and boxes, specialized [Local] classes are created.
///
/// Type variables can introduce locals in factories and constructors
/// but since one type variable can introduce different locals in different
/// factories and constructors it is not itself a [Local] but instead
/// a non-element [Local] is created through a specialized class.
abstract class Local extends Entity {}
/// The structure of function parameters.
class ParameterStructure {
/// Tag used for identifying serialized [ParameterStructure] objects in a
/// debugging data stream.
static const String tag = 'parameter-structure';
/// The number of required (positional) parameters.
final int requiredParameters;
/// The number of positional parameters.
final int positionalParameters;
/// The named parameters sorted alphabetically.
final List<String> namedParameters;
/// The number of type parameters.
final int typeParameters;
const ParameterStructure(this.requiredParameters, this.positionalParameters,
this.namedParameters, this.typeParameters);
const ParameterStructure.getter() : this(0, 0, const <String>[], 0);
const ParameterStructure.setter() : this(1, 1, const <String>[], 0);
factory ParameterStructure.fromType(FunctionType type) {
return new ParameterStructure(
type.parameterTypes.length,
type.parameterTypes.length + type.optionalParameterTypes.length,
type.namedParameters,
type.typeVariables.length);
}
/// Deserializes a [ParameterStructure] object from [source].
factory ParameterStructure.readFromDataSource(DataSource source) {
source.begin(tag);
int requiredParameters = source.readInt();
int positionalParameters = source.readInt();
List<String> namedParameters = source.readStrings();
int typeParameters = source.readInt();
source.end(tag);
return new ParameterStructure(requiredParameters, positionalParameters,
namedParameters, typeParameters);
}
/// Serializes this [ParameterStructure] to [sink].
void writeToDataSink(DataSink sink) {
sink.begin(tag);
sink.writeInt(requiredParameters);
sink.writeInt(positionalParameters);
sink.writeStrings(namedParameters);
sink.writeInt(typeParameters);
sink.end(tag);
}
/// The number of optional parameters (positional or named).
int get optionalParameters =>
positionalParameters - requiredParameters + namedParameters.length;
/// The total number of parameters (required or optional).
int get totalParameters => positionalParameters + namedParameters.length;
/// Returns the [CallStructure] corresponding to a call site passing all
/// parameters both required and optional.
CallStructure get callStructure {
return new CallStructure(positionalParameters + namedParameters.length,
namedParameters, typeParameters);
}
@override
int get hashCode => Hashing.listHash(
namedParameters,
Hashing.objectHash(
positionalParameters,
Hashing.objectHash(
requiredParameters, Hashing.objectHash(typeParameters))));
@override
bool operator ==(other) {
if (identical(this, other)) return true;
if (other is! ParameterStructure) return false;
if (requiredParameters != other.requiredParameters ||
positionalParameters != other.positionalParameters ||
typeParameters != other.typeParameters ||
namedParameters.length != other.namedParameters.length) {
return false;
}
for (int i = 0; i < namedParameters.length; i++) {
if (namedParameters[i] != other.namedParameters[i]) {
return false;
}
}
return true;
}
/// Short textual representation use for testing.
String get shortText {
StringBuffer sb = new StringBuffer();
if (typeParameters != 0) {
sb.write('<');
sb.write(typeParameters);
sb.write('>');
}
sb.write('(');
sb.write(positionalParameters);
if (namedParameters.length > 0) {
sb.write(',');
sb.write(namedParameters.join(','));
}
sb.write(')');
return sb.toString();
}
@override
String toString() {
StringBuffer sb = new StringBuffer();
sb.write('ParameterStructure(');
sb.write('requiredParameters=$requiredParameters,');
sb.write('positionalParameters=$positionalParameters,');
sb.write('namedParameters={${namedParameters.join(',')}},');
sb.write('typeParameters=$typeParameters)');
return sb.toString();
}
int get size =>
positionalParameters + typeParameters + namedParameters.length;
}