// 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;

  /// Returns whether or not this library has opted into null safety.
  bool get isNonNullableByDefault;
}

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

/// Values for variance annotations.
/// This needs to be kept in sync with values of `Variance` in `dart:_rti`.
enum Variance { legacyCovariant, covariant, contravariant, invariant }

/// 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 requiredPositionalParameters;

  /// The number of positional parameters.
  final int positionalParameters;

  /// All named parameters sorted alphabetically.
  final List<String> namedParameters;

  /// The required named parameters.
  final Set<String> requiredNamedParameters;

  /// The number of type parameters.
  final int typeParameters;

  const ParameterStructure(
      this.requiredPositionalParameters,
      this.positionalParameters,
      this.namedParameters,
      this.requiredNamedParameters,
      this.typeParameters);

  const ParameterStructure.getter()
      : this(0, 0, const <String>[], const <String>{}, 0);

  const ParameterStructure.setter()
      : this(1, 1, const <String>[], const <String>{}, 0);

  factory ParameterStructure.fromType(FunctionType type) {
    return new ParameterStructure(
        type.parameterTypes.length,
        type.parameterTypes.length + type.optionalParameterTypes.length,
        type.namedParameters,
        type.requiredNamedParameters,
        type.typeVariables.length);
  }

  /// Deserializes a [ParameterStructure] object from [source].
  factory ParameterStructure.readFromDataSource(DataSource source) {
    source.begin(tag);
    int requiredPositionalParameters = source.readInt();
    int positionalParameters = source.readInt();
    List<String> namedParameters = source.readStrings();
    Set<String> requiredNamedParameters =
        source.readStrings(emptyAsNull: true)?.toSet() ?? const <String>{};
    int typeParameters = source.readInt();
    source.end(tag);
    return new ParameterStructure(
        requiredPositionalParameters,
        positionalParameters,
        namedParameters,
        requiredNamedParameters,
        typeParameters);
  }

  /// Serializes this [ParameterStructure] to [sink].
  void writeToDataSink(DataSink sink) {
    sink.begin(tag);
    sink.writeInt(requiredPositionalParameters);
    sink.writeInt(positionalParameters);
    sink.writeStrings(namedParameters);
    sink.writeStrings(requiredNamedParameters);
    sink.writeInt(typeParameters);
    sink.end(tag);
  }

  /// The number of optional parameters (positional or named).
  int get optionalParameters =>
      (positionalParameters - requiredPositionalParameters) +
      (namedParameters.length - requiredNamedParameters.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(totalParameters, namedParameters, typeParameters);
  }

  @override
  int get hashCode => Hashing.listHash(
      namedParameters,
      Hashing.setHash(
          requiredNamedParameters,
          Hashing.objectHash(
              positionalParameters,
              Hashing.objectHash(requiredPositionalParameters,
                  Hashing.objectHash(typeParameters)))));

  @override
  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is! ParameterStructure) return false;
    if (requiredPositionalParameters != other.requiredPositionalParameters ||
        positionalParameters != other.positionalParameters ||
        typeParameters != other.typeParameters ||
        namedParameters.length != other.namedParameters.length ||
        requiredNamedParameters.length !=
            other.requiredNamedParameters.length) {
      return false;
    }
    for (int i = 0; i < namedParameters.length; i++) {
      if (namedParameters[i] != other.namedParameters[i]) {
        return false;
      }
    }
    for (String name in requiredNamedParameters) {
      if (!other.requiredNamedParameters.contains(name)) 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);
    for (var name in namedParameters) {
      sb.write(',');
      if (requiredNamedParameters.contains(name)) sb.write('req ');
      sb.write(name);
    }
    sb.write(')');
    return sb.toString();
  }

  @override
  String toString() {
    StringBuffer sb = new StringBuffer();
    sb.write('ParameterStructure(');
    sb.write('requiredPositionalParameters=$requiredPositionalParameters,');
    sb.write('positionalParameters=$positionalParameters,');
    sb.write('namedParameters={${namedParameters.join(',')}},');
    sb.write('requiredNamedParameters={${requiredNamedParameters.join(',')}},');
    sb.write('typeParameters=$typeParameters)');
    return sb.toString();
  }

  int get size => totalParameters + typeParameters;
}
