// Copyright (c) 2017, 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 '../closure.dart';
import '../common.dart';
import '../common/tasks.dart';
import '../elements/entities.dart';
import '../elements/names.dart' show Name;
import '../kernel/element_map.dart';
import '../world.dart';
import 'elements.dart';
import 'closure_visitors.dart';
import 'locals.dart';
import 'js_strategy.dart' show JsClosedWorld;

class KernelClosureAnalysis {
  /// Inspect members and mark if those members capture any state that needs to
  /// be marked as free variables.
  static ClosureModel computeClosureModel(MemberEntity entity, ir.Member node) {
    if (entity.isAbstract) return null;
    if (entity.isField && !entity.isInstanceMember) {
      ir.Field field = node;
      // Skip top-level/static fields without an initializer.
      if (field.initializer == null) return null;
    }

    ClosureModel model = new ClosureModel();
    CapturedScopeBuilder translator = new CapturedScopeBuilder(model,
        hasThisLocal: entity.isInstanceMember || entity.isConstructor);
    if (entity.isField) {
      if (node is ir.Field && node.initializer != null) {
        translator.translateLazyInitializer(node);
      }
    } else {
      assert(node is ir.Procedure || node is ir.Constructor);
      translator.translateConstructorOrProcedure(node);
    }
    return model;
  }
}

/// Closure conversion code using our new Entity model. Closure conversion is
/// necessary because the semantics of closures are slightly different in Dart
/// than JavaScript. Closure conversion is separated out into two phases:
/// generation of a new (temporary) representation to store where variables need
/// to be hoisted/captured up at another level to re-write the closure, and then
/// the code generation phase where we generate elements and/or instructions to
/// represent this new code path.
///
/// For a general explanation of how closure conversion works at a high level,
/// check out:
/// http://siek.blogspot.com/2012/07/essence-of-closure-conversion.html or
/// http://matt.might.net/articles/closure-conversion/.
// TODO(efortuna): Change inheritance hierarchy so that the
// ClosureConversionTask doesn't inherit from ClosureTask because it's just a
// glorified timer.
class KernelClosureConversionTask extends ClosureConversionTask<ir.Node> {
  final KernelToElementMapForBuilding _elementMap;
  final GlobalLocalsMap _globalLocalsMap;
  final Map<MemberEntity, ClosureModel> _closureModels;

  /// Map of the scoping information that corresponds to a particular entity.
  Map<Entity, ScopeInfo> _scopeMap = <Entity, ScopeInfo>{};
  Map<ir.Node, CapturedScope> _capturedScopesMap = <ir.Node, CapturedScope>{};

  Map<Entity, ClosureRepresentationInfo> _closureRepresentationMap =
      <Entity, ClosureRepresentationInfo>{};

  KernelClosureConversionTask(Measurer measurer, this._elementMap,
      this._globalLocalsMap, this._closureModels)
      : super(measurer);

  /// The combined steps of generating our intermediate representation of
  /// closures that need to be rewritten and generating the element model.
  /// Ultimately these two steps will be split apart with the second step
  /// happening later in compilation just before codegen. These steps are
  /// combined here currently to provide a consistent interface to the rest of
  /// the compiler until we are ready to separate these phases.
  @override
  void convertClosures(Iterable<MemberEntity> processedEntities,
      ClosedWorldRefiner closedWorldRefiner) {
    _createClosureEntities(_closureModels, closedWorldRefiner);
  }

  void _createClosureEntities(Map<MemberEntity, ClosureModel> closureModels,
      JsClosedWorld closedWorldRefiner) {
    closureModels.forEach((MemberEntity member, ClosureModel model) {
      KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
      if (model.scopeInfo != null) {
        _scopeMap[member] = new JsScopeInfo.from(model.scopeInfo, localsMap);
      }

      model.capturedScopesMap
          .forEach((ir.Node node, KernelCapturedScope scope) {
        if (scope is KernelCapturedLoopScope) {
          _capturedScopesMap[node] =
              new JsCapturedLoopScope.from(scope, localsMap);
        } else {
          _capturedScopesMap[node] = new JsCapturedScope.from(scope, localsMap);
        }
      });

      Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate =
          model.closuresToGenerate;
      for (ir.FunctionNode node in closuresToGenerate.keys) {
        _produceSyntheticElements(
            member, node, closuresToGenerate[node], closedWorldRefiner);
      }
    });
  }

  /// Given what variables are captured at each point, construct closure classes
  /// with fields containing the captured variables to replicate the Dart
  /// closure semantics in JS. If this closure captures any variables (meaning
  /// the closure accesses a variable that gets accessed at some point), then
  /// boxForCapturedVariables stores the local context for those variables.
  /// If no variables are captured, this parameter is null.
  void _produceSyntheticElements(MemberEntity member, ir.FunctionNode node,
      KernelScopeInfo info, JsClosedWorld closedWorldRefiner) {
    KernelToLocalsMap localsMap = _globalLocalsMap.getLocalsMap(member);
    KernelClosureClass closureClass = closedWorldRefiner.buildClosureClass(
        member, node, member.library, info, node.location, localsMap);

    // We want the original declaration where that function is used to point
    // to the correct closure class.
    _closureRepresentationMap[closureClass.callMethod] = closureClass;
    Entity entity = localsMap.getLocalFunction(node.parent);
    assert(entity != null);
    _closureRepresentationMap[entity] = closureClass;
  }

  @override
  ScopeInfo getScopeInfo(Entity entity) {
    // TODO(johnniwinther): Remove this check when constructor bodies a created
    // eagerly with the J-model; a constructor body should have it's own
    // [ClosureRepresentationInfo].
    if (entity is ConstructorBodyEntity) {
      ConstructorBodyEntity constructorBody = entity;
      entity = constructorBody.constructor;
    }

    return _scopeMap[entity] ?? getClosureRepresentationInfo(entity);
  }

  // TODO(efortuna): Eventually capturedScopesMap[node] should always
  // be non-null, and we should just test that with an assert.
  @override
  CapturedScope getCapturedScope(MemberEntity entity) {
    MemberDefinition definition = _elementMap.getMemberDefinition(entity);
    switch (definition.kind) {
      case MemberKind.regular:
      case MemberKind.constructor:
      case MemberKind.constructorBody:
        return _capturedScopesMap[definition.node] ?? const CapturedScope();
      default:
        throw failedAt(entity, "Unexpected member definition $definition");
    }
  }

  @override
  // TODO(efortuna): Eventually capturedScopesMap[node] should always
  // be non-null, and we should just test that with an assert.
  CapturedLoopScope getCapturedLoopScope(ir.Node loopNode) =>
      _capturedScopesMap[loopNode] ?? const CapturedLoopScope();

  @override
  // TODO(efortuna): Eventually closureRepresentationMap[node] should always be
  // non-null, and we should just test that with an assert.
  ClosureRepresentationInfo getClosureRepresentationInfo(Entity entity) {
    return _closureRepresentationMap[entity] ??
        const ClosureRepresentationInfo();
  }
}

class KernelScopeInfo {
  final Set<ir.VariableDeclaration> localsUsedInTryOrSync;
  final bool hasThisLocal;
  final Set<ir.VariableDeclaration> boxedVariables;

  /// The set of variables that were defined in another scope, but are used in
  /// this scope.
  Set<ir.VariableDeclaration> freeVariables = new Set<ir.VariableDeclaration>();

  KernelScopeInfo(this.hasThisLocal)
      : localsUsedInTryOrSync = new Set<ir.VariableDeclaration>(),
        boxedVariables = new Set<ir.VariableDeclaration>();

  KernelScopeInfo.from(this.hasThisLocal, KernelScopeInfo info)
      : localsUsedInTryOrSync = info.localsUsedInTryOrSync,
        boxedVariables = info.boxedVariables;

  KernelScopeInfo.withBoxedVariables(this.boxedVariables,
      this.localsUsedInTryOrSync, this.freeVariables, this.hasThisLocal);

  String toString() {
    StringBuffer sb = new StringBuffer();
    sb.write('this=$hasThisLocal,');
    sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
    return sb.toString();
  }
}

class JsScopeInfo extends ScopeInfo {
  final Set<Local> localsUsedInTryOrSync;
  final Local thisLocal;
  final Set<Local> boxedVariables;

  /// The set of variables that were defined in another scope, but are used in
  /// this scope.
  final Set<Local> freeVariables;

  JsScopeInfo(this.thisLocal, this.localsUsedInTryOrSync, this.boxedVariables,
      this.freeVariables);

  JsScopeInfo.from(KernelScopeInfo info, KernelToLocalsMap localsMap)
      : this.thisLocal =
            info.hasThisLocal ? new ThisLocal(localsMap.currentMember) : null,
        this.localsUsedInTryOrSync =
            info.localsUsedInTryOrSync.map(localsMap.getLocalVariable).toSet(),
        this.boxedVariables =
            info.boxedVariables.map(localsMap.getLocalVariable).toSet(),
        this.freeVariables =
            info.freeVariables.map(localsMap.getLocalVariable).toSet();

  void forEachBoxedVariable(f(Local local, FieldEntity field)) {
    boxedVariables.forEach((Local l) {
      // TODO(efortuna): add FieldEntities as created.
      f(l, null);
    });
  }

  bool localIsUsedInTryOrSync(Local variable) =>
      localsUsedInTryOrSync.contains(variable);

  String toString() {
    StringBuffer sb = new StringBuffer();
    sb.write('this=$thisLocal,');
    sb.write('localsUsedInTryOrSync={${localsUsedInTryOrSync.join(', ')}}');
    return sb.toString();
  }

  bool isBoxed(Local variable) => boxedVariables.contains(variable);
}

class KernelCapturedScope extends KernelScopeInfo {
  final ir.TreeNode context;

  KernelCapturedScope(
      Set<ir.VariableDeclaration> boxedVariables,
      this.context,
      Set<ir.VariableDeclaration> localsUsedInTryOrSync,
      Set<ir.VariableDeclaration> freeVariables,
      bool hasThisLocal)
      : super.withBoxedVariables(
            boxedVariables, localsUsedInTryOrSync, freeVariables, hasThisLocal);

  bool get requiresContextBox => boxedVariables.isNotEmpty;
}

class JsCapturedScope extends JsScopeInfo implements CapturedScope {
  final Local context;

  JsCapturedScope.from(
      KernelCapturedScope capturedScope, KernelToLocalsMap localsMap)
      : this.context = localsMap.getLocalVariable(capturedScope.context),
        super.from(capturedScope, localsMap);

  bool get requiresContextBox => boxedVariables.isNotEmpty;
}

class KernelCapturedLoopScope extends KernelCapturedScope {
  final List<ir.VariableDeclaration> boxedLoopVariables;

  KernelCapturedLoopScope(
      Set<ir.VariableDeclaration> boxedVariables,
      this.boxedLoopVariables,
      ir.TreeNode context,
      Set<ir.VariableDeclaration> localsUsedInTryOrSync,
      Set<ir.VariableDeclaration> freeVariables,
      bool hasThisLocal)
      : super(boxedVariables, context, localsUsedInTryOrSync, freeVariables,
            hasThisLocal);

  bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
}

class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope {
  final List<Local> boxedLoopVariables;

  JsCapturedLoopScope.from(
      KernelCapturedLoopScope capturedScope, KernelToLocalsMap localsMap)
      : this.boxedLoopVariables = capturedScope.boxedLoopVariables
            .map(localsMap.getLocalVariable)
            .toList(),
        super.from(capturedScope, localsMap);

  bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
}

// TODO(johnniwinther): Add unittest for the computed [ClosureClass].
class KernelClosureClass extends JsScopeInfo
    implements ClosureRepresentationInfo, JClass {
  final ir.Location location;

  final String name;
  final JLibrary library;
  JFunction callMethod;

  /// Index into the classData, classList and classEnvironment lists where this
  /// entity is stored in [JsToFrontendMapImpl].
  final int classIndex;

  final Map<Local, JField> localToFieldMap = new Map<Local, JField>();

  KernelClosureClass.fromScopeInfo(this.name, this.classIndex, this.library,
      KernelScopeInfo info, this.location, KernelToLocalsMap localsMap)
      : super.from(info, localsMap);

  // TODO(efortuna): Implement.
  Local get closureEntity => null;

  ClassEntity get closureClassEntity => this;

  List<Local> get createdFieldEntities => localToFieldMap.keys.toList();

  // TODO(efortuna): Implement.
  FieldEntity get thisFieldEntity => null;

  void forEachCapturedVariable(f(Local from, JField to)) {
    localToFieldMap.forEach(f);
  }

  // TODO(efortuna): Implement.
  @override
  void forEachBoxedVariable(f(Local local, JField field)) {}

  // TODO(efortuna): Implement.
  void forEachFreeVariable(f(Local variable, JField field)) {}

  // TODO(efortuna): Implement.
  bool isVariableBoxed(Local variable) => false;

  bool get isClosure => true;

  bool get isAbstract => false;

  String toString() => '${jsElementPrefix}class($name)';
}

class JClosureField extends JField {
  JClosureField(String name, int memberIndex,
      KernelClosureClass containingClass, bool isConst, bool isAssignable)
      : super(memberIndex, containingClass.library, containingClass,
            new Name(name, containingClass.library),
            isAssignable: isAssignable, isConst: isConst);
}

class ClosureClassDefinition implements ClassDefinition {
  final ClassEntity cls;
  final ir.Location location;

  ClosureClassDefinition(this.cls, this.location);

  ClassKind get kind => ClassKind.closure;

  ir.Node get node =>
      throw new UnsupportedError('ClosureClassDefinition.node for $cls');

  String toString() =>
      'ClosureClassDefinition(kind:$kind,cls:$cls,location:$location)';
}

class ClosureMemberDefinition implements MemberDefinition {
  final MemberEntity member;
  final ir.Location location;
  final MemberKind kind;
  final ir.Node node;

  ClosureMemberDefinition(this.member, this.location, this.kind, this.node);

  String toString() =>
      'ClosureMemberDefinition(kind:$kind,member:$member,location:$location)';
}

/// Collection of closure data collected for a single member.
class ClosureModel {
  /// Collection [ScopeInfo] data for the member, if any.
  // TODO(johnniwinther): [scopeInfo] seem to be missing only for fields
  // without initializers; we shouldn't even create a [ClosureModel] in these
  // cases.
  KernelScopeInfo scopeInfo;

  /// Collected [CapturedScope] data for nodes.
  Map<ir.Node, KernelCapturedScope> capturedScopesMap =
      <ir.Node, KernelCapturedScope>{};

  /// Collected [ScopeInfo] data for nodes.
  Map<ir.FunctionNode, KernelScopeInfo> closuresToGenerate =
      <ir.FunctionNode, KernelScopeInfo>{};
}
