// 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' show Spannable;
import '../serialization/serialization.dart';
import '../universe/call_structure.dart' show CallStructure;
import '../util/util.dart';
import 'names.dart';
import 'types.dart' show FunctionType;

/// 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 {
  // Not all entities have names. Imports with no prefix and some local
  // variables are unnamed. Some entities have a name that is the empty string
  // (e.g. the default constructor).
  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 {
  /// Classes always have a name.
  @override
  String get name;

  /// 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 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 {}

/// 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 {}

/// 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 = AsyncMarker._(AsyncModifier.Sync);

  /// The `sync*` function body marker.
  static const AsyncMarker SYNC_STAR =
      AsyncMarker._(AsyncModifier.SyncStar, isYielding: true);

  /// The `async` function body marker.
  static const AsyncMarker ASYNC =
      AsyncMarker._(AsyncModifier.Async, isAsync: true);

  /// The `async*` function body marker.
  static const AsyncMarker ASYNC_STAR =
      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 = <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 {
  // Constructors always have an enclosing class.
  @override
  ClassEntity get enclosingClass;

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

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

  static const ParameterStructure getter =
      ParameterStructure._(0, 0, [], {}, 0);

  static const ParameterStructure setter =
      ParameterStructure._(1, 1, [], {}, 0);

  static const ParameterStructure zeroArguments =
      ParameterStructure._(0, 0, [], {}, 0);

  static const ParameterStructure oneArgument =
      ParameterStructure._(1, 1, [], {}, 0);

  static const ParameterStructure twoArguments =
      ParameterStructure._(2, 2, [], {}, 0);

  static const List<ParameterStructure> _simple = [
    ParameterStructure._(0, 0, [], {}, 0),
    ParameterStructure._(1, 1, [], {}, 0),
    ParameterStructure._(2, 2, [], {}, 0),
    ParameterStructure._(3, 3, [], {}, 0),
    ParameterStructure._(4, 4, [], {}, 0),
    ParameterStructure._(5, 5, [], {}, 0),
  ];

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

  factory ParameterStructure(
      int requiredPositionalParameters,
      int positionalParameters,
      List<String> namedParameters,
      Set<String> requiredNamedParameters,
      int typeParameters) {
    // This simple canonicalization reduces the number of ParameterStructure
    // objects by over 90%.
    if (requiredPositionalParameters == positionalParameters &&
        namedParameters.isEmpty &&
        requiredNamedParameters.isEmpty &&
        typeParameters == 0 &&
        positionalParameters < _simple.length) {
      return _simple[positionalParameters];
    }

    // Force sharing of empty collections.
    if (namedParameters.isEmpty) namedParameters = const [];
    if (requiredNamedParameters.isEmpty) requiredNamedParameters = const {};

    return ParameterStructure._(
      requiredPositionalParameters,
      positionalParameters,
      namedParameters,
      requiredNamedParameters,
      typeParameters,
    );
  }

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

  /// Deserializes a [ParameterStructure] object from [source].
  static readFromDataSource(DataSourceReader source) {
    final tag = ParameterStructure.tag;
    source.begin(tag);
    int requiredPositionalParameters = source.readInt();
    int positionalParameters = source.readInt();
    List<String> namedParameters = source.readStrings();
    Set<String> requiredNamedParameters =
        source.readStringsOrNull()?.toSet() ?? const <String>{};
    int typeParameters = source.readInt();
    source.end(tag);
    return ParameterStructure(
        requiredPositionalParameters,
        positionalParameters,
        namedParameters,
        requiredNamedParameters,
        typeParameters);
  }

  /// Serializes this [ParameterStructure] to [sink].
  void writeToDataSink(DataSinkWriter sink) {
    final tag = ParameterStructure.tag;
    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 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 = 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 = 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;
}
