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

library dart2js.common.codegen;

import '../common.dart';
import '../common/backend_api.dart' show Backend;
import '../constants/values.dart' show ConstantValue;
import '../elements/resolution_types.dart'
    show ResolutionDartType, ResolutionInterfaceType;
import '../elements/elements.dart'
    show
        AstElement,
        ClassElement,
        Element,
        FunctionElement,
        LocalFunctionElement,
        ResolvedAst;
import '../enqueue.dart' show Enqueuer;
import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
import '../universe/world_impact.dart'
    show WorldImpact, WorldImpactBuilderImpl, WorldImpactVisitor;
import '../util/util.dart' show Pair, Setlet;
import 'work.dart' show WorkItem;

class CodegenImpact extends WorldImpact {
  const CodegenImpact();

  Iterable<ConstantValue> get compileTimeConstants => const <ConstantValue>[];

  Iterable<Pair<ResolutionDartType, ResolutionDartType>>
      get typeVariableBoundsSubtypeChecks {
    return const <Pair<ResolutionDartType, ResolutionDartType>>[];
  }

  Iterable<String> get constSymbols => const <String>[];

  Iterable<Set<ClassElement>> get specializedGetInterceptors {
    return const <Set<ClassElement>>[];
  }

  bool get usesInterceptor => false;

  Iterable<ClassElement> get typeConstants => const <ClassElement>[];

  Iterable<Element> get asyncMarkers => const <FunctionElement>[];
}

class _CodegenImpact extends WorldImpactBuilderImpl implements CodegenImpact {
  Setlet<ConstantValue> _compileTimeConstants;
  Setlet<Pair<ResolutionDartType, ResolutionDartType>>
      _typeVariableBoundsSubtypeChecks;
  Setlet<String> _constSymbols;
  List<Set<ClassElement>> _specializedGetInterceptors;
  bool _usesInterceptor = false;
  Setlet<ClassElement> _typeConstants;
  Setlet<FunctionElement> _asyncMarkers;

  _CodegenImpact();

  void apply(WorldImpactVisitor visitor) {
    staticUses.forEach(visitor.visitStaticUse);
    dynamicUses.forEach(visitor.visitDynamicUse);
    typeUses.forEach(visitor.visitTypeUse);
  }

  void registerCompileTimeConstant(ConstantValue constant) {
    if (_compileTimeConstants == null) {
      _compileTimeConstants = new Setlet<ConstantValue>();
    }
    _compileTimeConstants.add(constant);
  }

  Iterable<ConstantValue> get compileTimeConstants {
    return _compileTimeConstants != null
        ? _compileTimeConstants
        : const <ConstantValue>[];
  }

  void registerTypeVariableBoundsSubtypeCheck(
      ResolutionDartType subtype, ResolutionDartType supertype) {
    if (_typeVariableBoundsSubtypeChecks == null) {
      _typeVariableBoundsSubtypeChecks =
          new Setlet<Pair<ResolutionDartType, ResolutionDartType>>();
    }
    _typeVariableBoundsSubtypeChecks.add(
        new Pair<ResolutionDartType, ResolutionDartType>(subtype, supertype));
  }

  Iterable<Pair<ResolutionDartType, ResolutionDartType>>
      get typeVariableBoundsSubtypeChecks {
    return _typeVariableBoundsSubtypeChecks != null
        ? _typeVariableBoundsSubtypeChecks
        : const <Pair<ResolutionDartType, ResolutionDartType>>[];
  }

  void registerConstSymbol(String name) {
    if (_constSymbols == null) {
      _constSymbols = new Setlet<String>();
    }
    _constSymbols.add(name);
  }

  Iterable<String> get constSymbols {
    return _constSymbols != null ? _constSymbols : const <String>[];
  }

  void registerSpecializedGetInterceptor(Set<ClassElement> classes) {
    if (_specializedGetInterceptors == null) {
      _specializedGetInterceptors = <Set<ClassElement>>[];
    }
    _specializedGetInterceptors.add(classes);
  }

  Iterable<Set<ClassElement>> get specializedGetInterceptors {
    return _specializedGetInterceptors != null
        ? _specializedGetInterceptors
        : const <Set<ClassElement>>[];
  }

  void registerUseInterceptor() {
    _usesInterceptor = true;
  }

  bool get usesInterceptor => _usesInterceptor;

  void registerTypeConstant(ClassElement element) {
    if (_typeConstants == null) {
      _typeConstants = new Setlet<ClassElement>();
    }
    _typeConstants.add(element);
  }

  Iterable<ClassElement> get typeConstants {
    return _typeConstants != null ? _typeConstants : const <ClassElement>[];
  }

  void registerAsyncMarker(FunctionElement element) {
    if (_asyncMarkers == null) {
      _asyncMarkers = new Setlet<FunctionElement>();
    }
    _asyncMarkers.add(element);
  }

  Iterable<Element> get asyncMarkers {
    return _asyncMarkers != null ? _asyncMarkers : const <FunctionElement>[];
  }
}

// TODO(johnniwinther): Split this class into interface and implementation.
// TODO(johnniwinther): Move this implementation to the JS backend.
class CodegenRegistry {
  final Element currentElement;
  final _CodegenImpact worldImpact;

  CodegenRegistry(AstElement currentElement)
      : this.currentElement = currentElement,
        this.worldImpact = new _CodegenImpact();

  bool get isForResolution => false;

  String toString() => 'CodegenRegistry for $currentElement';

  /// Add the uses in [impact] to the impact of this registry.
  void addImpact(WorldImpact impact) {
    worldImpact.addImpact(impact);
  }

  @deprecated
  void registerInstantiatedClass(ClassElement element) {
    registerInstantiation(element.rawType);
  }

  void registerStaticUse(StaticUse staticUse) {
    worldImpact.registerStaticUse(staticUse);
  }

  void registerDynamicUse(DynamicUse dynamicUse) {
    worldImpact.registerDynamicUse(dynamicUse);
  }

  void registerTypeUse(TypeUse typeUse) {
    worldImpact.registerTypeUse(typeUse);
  }

  void registerCompileTimeConstant(ConstantValue constant) {
    worldImpact.registerCompileTimeConstant(constant);
  }

  void registerTypeVariableBoundsSubtypeCheck(
      ResolutionDartType subtype, ResolutionDartType supertype) {
    worldImpact.registerTypeVariableBoundsSubtypeCheck(subtype, supertype);
  }

  void registerInstantiatedClosure(LocalFunctionElement element) {
    worldImpact.registerStaticUse(new StaticUse.closure(element));
  }

  void registerConstSymbol(String name) {
    worldImpact.registerConstSymbol(name);
  }

  void registerSpecializedGetInterceptor(Set<ClassElement> classes) {
    worldImpact.registerSpecializedGetInterceptor(classes);
  }

  void registerUseInterceptor() {
    worldImpact.registerUseInterceptor();
  }

  void registerTypeConstant(ClassElement element) {
    worldImpact.registerTypeConstant(element);
  }

  void registerInstantiation(ResolutionInterfaceType type) {
    registerTypeUse(new TypeUse.instantiation(type));
  }

  void registerAsyncMarker(FunctionElement element) {
    worldImpact.registerAsyncMarker(element);
  }
}

/// [WorkItem] used exclusively by the [CodegenEnqueuer].
class CodegenWorkItem extends WorkItem {
  CodegenRegistry registry;
  final ResolvedAst resolvedAst;
  final Backend backend;

  factory CodegenWorkItem(Backend backend, AstElement element) {
    // If this assertion fails, the resolution callbacks of the backend may be
    // missing call of form registry.registerXXX. Alternatively, the code
    // generation could spuriously be adding dependencies on things we know we
    // don't need.
    assert(invariant(element, element.hasResolvedAst,
        message: "$element has no resolved ast."));
    ResolvedAst resolvedAst = element.resolvedAst;
    return new CodegenWorkItem.internal(resolvedAst, backend);
  }

  CodegenWorkItem.internal(ResolvedAst resolvedAst, this.backend)
      : this.resolvedAst = resolvedAst,
        super(resolvedAst.element);

  WorldImpact run() {
    registry = new CodegenRegistry(element);
    return backend.codegen(this);
  }

  String toString() => 'CodegenWorkItem(${resolvedAst.element})';
}
