// Copyright (c) 2012, 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' as ir;
import 'common.dart';
import 'elements/entities.dart';
import 'js_model/closure.dart';
import 'js_model/element_map.dart';
import 'serialization/serialization.dart';

/// Class that provides information for how closures are rewritten/represented
/// to preserve Dart semantics when compiled to JavaScript. Given a particular
/// node to look up, it returns a information about the internal representation
/// of how closure conversion is implemented. T is an ir.Node or Node.
abstract class ClosureData {
  /// Deserializes a [ClosureData] object from [source].
  factory ClosureData.readFromDataSource(
          JsToElementMap elementMap, DataSourceReader source) =
      ClosureDataImpl.readFromDataSource;

  /// Serializes this [ClosureData] to [sink].
  void writeToDataSink(DataSinkWriter sink);

  /// Look up information about the variables that have been mutated and are
  /// used inside the scope of [node]. Assumes member is not abstract and
  /// therefore scope info exists.
  ScopeInfo getScopeInfo(MemberEntity member);

  ClosureRepresentationInfo getClosureInfo(ir.LocalFunction localFunction);

  /// Look up information about a loop, in case any variables it declares need
  /// to be boxed/snapshotted.
  CapturedLoopScope getCapturedLoopScope(ir.Node loopNode);

  /// Accessor to the information about scopes that closures capture. Used by
  /// the SSA builder.
  CapturedScope getCapturedScope(MemberEntity entity);

  /// If [entity] is a closure call method or closure signature method, the
  /// original enclosing member is returned. Otherwise [entity] is returned.
  ///
  /// A member and its nested closure share the underlying AST, we need to
  /// ensure that locals are shared between them. We therefore store the
  /// locals in the global locals map using the enclosing member as key.
  MemberEntity getEnclosingMember(MemberEntity entity);
}

/// Enum used for identifying [ScopeInfo] subclasses in serialization.
enum ScopeInfoKind {
  scopeInfo,
  capturedScope,
  capturedLoopScope,
  closureRepresentationInfo,
}

/// Class that represents one level of scoping information, whether this scope
/// is a closure or not. This is specifically used to store information
/// about the usage of variables in try or sync blocks, because they need to be
/// boxed.
///
/// Variables that are used in a try must be treated as boxed because the
/// control flow can be non-linear. Also parameters to a `sync*` generator must
/// be boxed, because of the way we rewrite sync* functions. See also comments
/// in [ClosureClassMap.useLocal].
class ScopeInfo {
  const ScopeInfo();

  /// Deserializes a [ScopeInfo] object from [source].
  factory ScopeInfo.readFromDataSource(DataSourceReader source) {
    ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
    switch (kind) {
      case ScopeInfoKind.scopeInfo:
        return JsScopeInfo.readFromDataSource(source);
      case ScopeInfoKind.capturedScope:
        return JsCapturedScope.readFromDataSource(source);
      case ScopeInfoKind.capturedLoopScope:
        return JsCapturedLoopScope.readFromDataSource(source);
      case ScopeInfoKind.closureRepresentationInfo:
        return JsClosureClassInfo.readFromDataSource(source);
    }
  }

  /// Serializes this [ScopeInfo] to [sink].
  void writeToDataSink(DataSinkWriter sink) {
    throw UnsupportedError('${runtimeType}.writeToDataSink');
  }

  /// Convenience reference pointer to the element representing `this`.
  /// If this scope is not in an instance member, it will be null.
  Local? get thisLocal => null;

  /// Returns true if this [variable] is used inside a `try` block or a `sync*`
  /// generator (this is important to know because boxing/redirection needs to
  /// happen for those local variables).
  ///
  /// Variables that are used in a try must be treated as boxed because the
  /// control flow can be non-linear.
  ///
  /// Also parameters to a `sync*` generator must be boxed, because of the way
  /// we rewrite sync* functions. See also comments in
  /// [ClosureClassMap.useLocal].
  bool localIsUsedInTryOrSync(KernelToLocalsMap localsMap, Local variable) =>
      false;

  /// Loop through each variable that has been defined in this scope, modified
  /// anywhere (this scope or another scope) and used in another scope. Because
  /// it is used in another scope, these variables need to be "boxed", creating
  /// a thin wrapper around accesses to these variables so that accesses get
  /// the correct updated value. The variables in localsUsedInTryOrSync may
  /// be included in this set.
  ///
  /// In the case of loops, this is the set of iteration variables (or any
  /// variables declared in the for loop expression (`for (...here...)`) that
  /// need to be boxed to snapshot their value.
  void forEachBoxedVariable(
      KernelToLocalsMap localsMap, f(Local local, FieldEntity field)) {}

  /// True if [variable] has been mutated and is also used in another scope.
  bool isBoxedVariable(KernelToLocalsMap localsMap, Local variable) => false;
}

/// Class representing the usage of a scope that has been captured in the
/// context of a closure.
class CapturedScope extends ScopeInfo {
  const CapturedScope();

  /// Deserializes a [CapturedScope] object from [source].
  factory CapturedScope.readFromDataSource(DataSourceReader source) {
    ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
    switch (kind) {
      case ScopeInfoKind.scopeInfo:
      case ScopeInfoKind.closureRepresentationInfo:
        throw UnsupportedError('Unexpected CapturedScope kind $kind');
      case ScopeInfoKind.capturedScope:
        return JsCapturedScope.readFromDataSource(source);
      case ScopeInfoKind.capturedLoopScope:
        return JsCapturedLoopScope.readFromDataSource(source);
    }
  }

  /// If true, this closure accesses a variable that was defined in an outside
  /// scope and this variable gets modified at some point (sometimes we say that
  /// variable has been "captured"). In this situation, access to this variable
  /// is controlled via a wrapper (box) so that updates to this variable
  /// are done in a way that is in line with Dart's closure rules.
  bool get requiresContextBox => false;

  /// Accessor to the local environment in which a particular closure node is
  /// executed. This will encapsulate the value of any variables that have been
  /// scoped into this context from outside. This is an accessor to the
  /// contextBox that [requiresContextBox] is testing is required.
  Local? get contextBox => null;
}

/// Class that describes the actual mechanics of how values of variables
/// instantiated in a loop are captured inside closures in the loop body.
/// Unlike JS, the value of a declared loop iteration variable in any closure
/// is captured/snapshotted inside at each iteration point, as if we created a
/// new local variable for that value inside the loop. For example, for the
/// following loop:
///
///     var lst = [];
///     for (int i = 0; i < 5; i++) lst.add(()=>i);
///     var result = list.map((f) => f()).toList();
///
/// `result` will be [0, 1, 2, 3, 4], whereas were this JS code
/// the result would be [5, 5, 5, 5, 5]. Because of this difference we need to
/// create a closure for these sorts of loops to capture the variable's value at
/// each iteration, by boxing the iteration variable[s].
class CapturedLoopScope extends CapturedScope {
  const CapturedLoopScope();

  /// Deserializes a [CapturedLoopScope] object from [source].
  factory CapturedLoopScope.readFromDataSource(DataSourceReader source) {
    ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
    switch (kind) {
      case ScopeInfoKind.scopeInfo:
      case ScopeInfoKind.closureRepresentationInfo:
      case ScopeInfoKind.capturedScope:
        throw UnsupportedError('Unexpected CapturedLoopScope kind $kind');
      case ScopeInfoKind.capturedLoopScope:
        return JsCapturedLoopScope.readFromDataSource(source);
    }
  }

  /// True if this loop scope declares in the first part of the loop
  /// `for (<here>;...;...)` any variables that need to be boxed.
  bool get hasBoxedLoopVariables => false;

  /// The set of iteration variables (or variables declared in the for loop
  /// expression (`for (<here>; ... ; ...)`) that need to be boxed to snapshot
  /// their value. These variables are also included in the set of
  /// `forEachBoxedVariable` method. The distinction between these two sets is
  /// in this example:
  ///
  ///     run(f) => f();
  ///     var a;
  ///     for (int i = 0; i < 3; i++) {
  ///       var b = 3;
  ///       a = () => b = i;
  ///     }
  ///
  /// `i` would be a part of the boxedLoopVariables AND boxedVariables, but b
  /// would only be a part of boxedVariables.
  List<Local> getBoxedLoopVariables(KernelToLocalsMap localsMap) =>
      const <Local>[];
}

/// Class that describes the actual mechanics of how the converted, rewritten
/// closure is implemented. For example, for the following closure (named foo
/// for convenience):
///
///   var foo = (x) => y + x;
///
/// We would produce the following class to control access to these variables in
/// the following way (modulo naming of variables, assuming that y is modified
/// elsewhere in its scope):
///
///    class FooClosure {
///       int y;
///       FooClosure(this.y);
///       call(x) => this.y + x;
///    }
///
///  and then to execute this closure, for example:
///
///     var foo = new FooClosure(1);
///     foo.call(2);
///
/// if `y` is modified elsewhere within its scope, accesses to y anywhere in the
/// code will be controlled via a box object.
///
/// Because in these examples `y` was declared in some other, outer scope, but
/// used in the inner scope of this closure, we say `y` is a "captured"
/// variable.
/// TODO(efortuna): Make interface simpler in subsequent refactorings.
class ClosureRepresentationInfo extends ScopeInfo {
  const ClosureRepresentationInfo();

  /// Deserializes a [ClosureRepresentationInfo] object from [source].
  factory ClosureRepresentationInfo.readFromDataSource(
      DataSourceReader source) {
    ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
    switch (kind) {
      case ScopeInfoKind.scopeInfo:
      case ScopeInfoKind.capturedScope:
      case ScopeInfoKind.capturedLoopScope:
        throw UnsupportedError(
            'Unexpected ClosureRepresentationInfo kind $kind');
      case ScopeInfoKind.closureRepresentationInfo:
        return JsClosureClassInfo.readFromDataSource(source);
    }
  }

  /// The original local function before any translation.
  ///
  /// Will be null for methods.
  Local? getClosureEntity(KernelToLocalsMap localsMap) => null;

  /// The entity for the class used to represent the rewritten closure in the
  /// emitted JavaScript.
  ///
  /// Closures are rewritten in the form of classes that have fields to control
  /// the redirection and editing of captured variables.
  ClassEntity? get closureClassEntity => null;

  /// The function that implements the [local] function as a `call` method on
  /// the closure class.
  FunctionEntity? get callMethod => null;

  /// The signature method for [callMethod] if needed.
  FunctionEntity? get signatureMethod => null;

  /// List of locals that this closure class has created corresponding field
  /// entities for.
  @deprecated
  List<Local> getCreatedFieldEntities(KernelToLocalsMap localsMap) =>
      const <Local>[];

  /// As shown in the example in the comments at the top of this class, we
  /// create fields in the closure class for each captured variable. This is an
  /// accessor the [local] for which [field] was created.
  /// Returns the [local] for which [field] was created.
  Local getLocalForField(KernelToLocalsMap localsMap, FieldEntity field) {
    failedAt(field, "No local for $field.");
  }

  /// Convenience pointer to the field entity representation in the closure
  /// class of the element representing `this`.
  FieldEntity? get thisFieldEntity => null;

  /// Loop through each variable that has been boxed in this closure class. Only
  /// captured variables that are mutated need to be "boxed" (which basically
  /// puts a thin layer between updates and reads to this variable to ensure
  /// that every place that accesses it gets the correct updated value). This
  /// includes looping over variables that were boxed from other scopes, not
  /// strictly variables defined in this closure, unlike the behavior in
  /// the superclass ScopeInfo.
  @override
  void forEachBoxedVariable(
      KernelToLocalsMap localsMap, f(Local local, FieldEntity field)) {}

  /// Loop through each free variable in this closure. Free variables are the
  /// variables that have been captured *just* in this closure, not in nested
  /// scopes.
  void forEachFreeVariable(
      KernelToLocalsMap localsMap, f(Local variable, FieldEntity field)) {}

  // TODO(efortuna): Remove this method. The old system was using
  // ClosureClassMaps for situations other than closure class maps, and that's
  // just confusing.
  bool get isClosure => false;
}

/// A type variable as a local variable.
class TypeVariableLocal implements Local {
  final TypeVariableEntity typeVariable;

  TypeVariableLocal(this.typeVariable);

  @override
  String? get name => typeVariable.name;

  @override
  int get hashCode => typeVariable.hashCode;

  @override
  bool operator ==(other) {
    if (other is! TypeVariableLocal) return false;
    return typeVariable == other.typeVariable;
  }

  @override
  String toString() {
    StringBuffer sb = StringBuffer();
    sb.write('type_variable_local(');
    sb.write(typeVariable);
    sb.write(')');
    return sb.toString();
  }
}

/// A local variable used encode the direct (uncaptured) references to [this].
class ThisLocal extends Local {
  final ClassEntity enclosingClass;

  ThisLocal(this.enclosingClass);

  @override
  String get name => 'this';

  @override
  bool operator ==(other) {
    return other is ThisLocal && other.enclosingClass == enclosingClass;
  }

  @override
  int get hashCode => enclosingClass.hashCode;
}

/// A local variable that contains the box object holding the [BoxFieldElement]
/// fields.
class BoxLocal extends Local {
  final ClassEntity container;

  BoxLocal(this.container);

  @override
  String get name => container.name;

  @override
  bool operator ==(other) {
    return other is BoxLocal && other.container == container;
  }

  @override
  int get hashCode => container.hashCode;

  @override
  String toString() => 'BoxLocal($name)';
}

///
/// Move the below classes to a JS model eventually.
///
abstract class JSEntity implements MemberEntity {
  String get declaredName;
}

abstract class PrivatelyNamedJSEntity implements JSEntity {
  Entity get rootOfScope;
}
