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

part of dart_backend;

// TODO(ahe): This class is simply wrong.  This backend should use
// elements when it can, not AST nodes.  Perhaps a [Map<Element,
// TreeElements>] is what is needed.
class ElementAst {
  final Node ast;
  final TreeElements treeElements;

  ElementAst(this.ast, this.treeElements);
}

class DartBackend extends Backend {
  final List<CompilerTask> tasks;
  final bool stripAsserts;

  bool get supportsReflection => true;

  // TODO(zarah) Maybe change this to a command-line option.
  // Right now, it is set by the tests.
  bool useMirrorHelperLibrary = false;

  /// Updated to a [MirrorRenamerImpl] instance if the [useMirrorHelperLibrary]
  /// field is set and mirror are needed.
  MirrorRenamer mirrorRenamer = const MirrorRenamer();

  final DartOutputter outputter;

  // Used in test.
  PlaceholderRenamer get placeholderRenamer => outputter.renamer;
  Map<ClassNode, List<Node>> get memberNodes => outputter.output.memberNodes;

  ConstantSystem get constantSystem {
    return constantCompilerTask.constantCompiler.constantSystem;
  }

  BackendConstantEnvironment get constants => constantCompilerTask;

  DartConstantTask constantCompilerTask;

  DartImpactTransformer impactTransformer;

  final Set<ClassElement> usedTypeLiterals = new Set<ClassElement>();

  /// The set of visible platform classes that are implemented by instantiated
  /// user classes.
  final Set<ClassElement> _userImplementedPlatformClasses =
      new Set<ClassElement>();

  bool enableCodegenWithErrorsIfSupported(Spannable node) {
    reporter.reportHintMessage(
        node,
        MessageKind.GENERIC,
        {'text': "Generation of code with compile time errors is not "
                 "supported for dart2dart."});
    return false;
  }

  /**
   * Tells whether it is safe to remove type declarations from variables,
   * functions parameters. It becomes not safe if:
   * 1) TypeError is used somewhere in the code,
   * 2) The code has typedefs in right hand side of IS checks,
   * 3) The code has classes which extend typedefs, have type arguments typedefs
   *    or type variable bounds typedefs.
   * These restrictions can be less strict.
   */
  bool isSafeToRemoveTypeDeclarations(
      Map<ClassElement, Iterable<Element>> classMembers) {
    ClassElement typeErrorElement = compiler.coreLibrary.find('TypeError');
    if (classMembers.containsKey(typeErrorElement) ||
        compiler.resolverWorld.isChecks.any(
            (DartType type) => type.element == typeErrorElement)) {
      return false;
    }
    Set<DartType> processedTypes = new Set<DartType>();
    List<DartType> workQueue = new List<DartType>();
    workQueue.addAll(
        classMembers.keys.map((classElement) => classElement.thisType));
    workQueue.addAll(compiler.resolverWorld.isChecks);

    while (!workQueue.isEmpty) {
      DartType type = workQueue.removeLast();
      if (processedTypes.contains(type)) continue;
      processedTypes.add(type);
      if (type is FunctionType) return false;
      if (type is TypedefType) return false;
      if (type is InterfaceType) {
        InterfaceType interfaceType = type;
        // Check all type arguments.
        interfaceType.typeArguments.forEach(workQueue.add);
        ClassElement element = type.element;
        // Check all supertypes.
        if (element.allSupertypes != null) {
          element.allSupertypes.forEach(workQueue.add);
        }
      }
    }
    return true;
  }

  DartBackend(Compiler compiler, List<String> strips, {bool multiFile})
      : tasks = <CompilerTask>[],
        stripAsserts = strips.indexOf('asserts') != -1,
        constantCompilerTask = new DartConstantTask(compiler),
        outputter = new DartOutputter(
            compiler.reporter, compiler.outputProvider,
            forceStripTypes: strips.indexOf('types') != -1,
            multiFile: multiFile,
            enableMinification: compiler.enableMinification),
        super(compiler) {
    impactTransformer = new DartImpactTransformer(this);
  }


  DiagnosticReporter get reporter => compiler.reporter;

  Resolution get resolution => compiler.resolution;

  bool classNeedsRti(ClassElement cls) => false;
  bool methodNeedsRti(FunctionElement function) => false;

  void enqueueHelpers(ResolutionEnqueuer world, Registry registry) {
    // Right now resolver doesn't always resolve interfaces needed
    // for literals, so force them. TODO(antonm): fix in the resolver.
    final LITERAL_TYPE_NAMES = const [
      'Map', 'List', 'num', 'int', 'double', 'bool'
    ];
    final coreLibrary = compiler.coreLibrary;
    for (final name in LITERAL_TYPE_NAMES) {
      ClassElement classElement = coreLibrary.findLocal(name);
      classElement.ensureResolved(resolution);
    }
    // Enqueue the methods that the VM might invoke on user objects because
    // we don't trust the resolution to always get these included.
    world.registerDynamicUse(new DynamicUse(Selectors.toString_, null));
    world.registerDynamicUse(
        new DynamicUse(Selectors.hashCode_, null));
    world.registerDynamicUse(
        new DynamicUse(new Selector.binaryOperator('=='), null));
    world.registerDynamicUse(
        new DynamicUse(Selectors.compareTo, null));
  }

  WorldImpact codegen(CodegenWorkItem work) {
    return const WorldImpact();
  }

  /**
   * Tells whether we should output given element. Corelib classes like
   * Object should not be in the resulting code.
   */
  @override
  bool shouldOutput(Element element) {
    return (!element.library.isPlatformLibrary &&
            !element.isSynthesized &&
            element is! AbstractFieldElement)
        || mirrorRenamer.isMirrorHelperLibrary(element.library);
  }

  int assembleProgram() {
    ElementAst computeElementAst(AstElement element) {
      return new ElementAst(element.resolvedAst.node,
                            element.resolvedAst.elements);
    }

    // TODO(johnniwinther): Remove the need for this method.
    void postProcessElementAst(
        AstElement element, ElementAst elementAst,
        newTypedefElementCallback,
        newClassElementCallback) {
      ReferencedElementCollector collector =
          new ReferencedElementCollector(reporter,
                                         element,
                                         elementAst,
                                         newTypedefElementCallback,
                                         newClassElementCallback);
      collector.collect();
    }

    int totalSize = outputter.assembleProgram(
        libraries: compiler.libraryLoader.libraries,
        instantiatedClasses: compiler.resolverWorld.directlyInstantiatedClasses,
        resolvedElements: compiler.enqueuer.resolution.processedElements,
        usedTypeLiterals: usedTypeLiterals,
        postProcessElementAst: postProcessElementAst,
        computeElementAst: computeElementAst,
        shouldOutput: shouldOutput,
        isSafeToRemoveTypeDeclarations: isSafeToRemoveTypeDeclarations,
        sortElements: Elements.sortedByPosition,
        mirrorRenamer: mirrorRenamer,
        mainFunction: compiler.mainFunction,
        outputUri: compiler.outputUri);

    // Output verbose info about size ratio of resulting bundle to all
    // referenced non-platform sources.
    logResultBundleSizeInfo(
        outputter.libraryInfo.userLibraries,
        outputter.elementInfo.topLevelElements,
        totalSize);

    return totalSize;
  }

  void logResultBundleSizeInfo(Iterable<LibraryElement> userLibraries,
                               Iterable<Element> topLevelElements,
                               int totalOutputSize) {
    // Sum total size of scripts in each referenced library.
    int nonPlatformSize = 0;
    for (LibraryElement lib in userLibraries) {
      for (CompilationUnitElement compilationUnit in lib.compilationUnits) {
        nonPlatformSize += compilationUnit.script.file.length;
      }
    }
    int percentage = totalOutputSize * 100 ~/ nonPlatformSize;
    log('Total used non-platform files size: ${nonPlatformSize} bytes, '
        'Output total size: $totalOutputSize bytes (${percentage}%)');
  }

  log(String message) => reporter.log('[DartBackend] $message');

  @override
  Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
    // All platform classes must be resolved to ensure that their member names
    // are preserved.
    loadedLibraries.forEachLibrary((LibraryElement library) {
      if (library.isPlatformLibrary) {
        library.forEachLocalMember((Element element) {
          if (element.isClass) {
            ClassElement classElement = element;
            classElement.ensureResolved(resolution);
          }
        });
      }
    });
    if (useMirrorHelperLibrary &&
        loadedLibraries.containsLibrary(Uris.dart_mirrors)) {
      return compiler.libraryLoader.loadLibrary(
          compiler.translateResolvedUri(
              loadedLibraries.getLibrary(Uris.dart_mirrors),
              MirrorRenamerImpl.DART_MIRROR_HELPER, null)).
          then((LibraryElement library) {
        mirrorRenamer = new MirrorRenamerImpl(compiler, this, library);
      });
    }
    return new Future.value();
  }

  @override
  void registerStaticUse(Element element, Enqueuer enqueuer) {
    if (element == compiler.mirrorSystemGetNameFunction) {
      FunctionElement getNameFunction = mirrorRenamer.getNameFunction;
      if (getNameFunction != null) {
        enqueuer.addToWorkList(getNameFunction);
      }
    }
  }

  @override
  void registerInstantiatedType(InterfaceType type,
                                Enqueuer enqueuer,
                                Registry registry,
                                {bool mirrorUsage: false}) {
    registerPlatformMembers(type, registerUse: registry.registerDynamicUse);
    super.registerInstantiatedType(
        type, enqueuer, registry, mirrorUsage: mirrorUsage);
  }

  /// Register dynamic access of members of [type] that implement members
  /// of types defined in the platform libraries.
  void registerPlatformMembers(
      InterfaceType type,
      {void registerUse(DynamicUse dynamicUse)}) {

    // Without patching, dart2dart has no way of performing sound tree-shaking
    // in face external functions. Therefore we employ another scheme:
    //
    // Based on the assumption that the platform code only relies on the
    // interfaces of it's own classes, we can approximate the semantics of
    // external functions by eagerly registering dynamic invocation of instance
    // members defined the platform interfaces.
    //
    // Since we only need to generate code for non-platform classes we can
    // restrict this registration to platform interfaces implemented by
    // instantiated non-platform classes.
    //
    // Consider for instance this program:
    //
    //     import 'dart:math' show Random;
    //
    //     class MyRandom implements Random {
    //       int nextInt() => 0;
    //     }
    //
    //     main() {
    //       print([0, 1, 2].shuffle(new MyRandom()));
    //     }
    //
    // Here `MyRandom` is a subtype if `Random` defined in 'dart:math'. By the
    // assumption, all methods defined `Random` are potentially called, and
    // therefore, though there are no visible call sites from the user node,
    // dynamic invocation of for instance `nextInt` should be registered. In
    // this case, `nextInt` is actually called by the standard implementation of
    // `shuffle`.

    ClassElement cls = type.element;
    if (!cls.library.isPlatformLibrary) {
      for (Link<DartType> link = cls.allSupertypes;
           !link.isEmpty;
           link = link.tail) {
        InterfaceType supertype = link.head;
        ClassElement superclass = supertype.element;
        LibraryElement library = superclass.library;
        if (library.isPlatformLibrary) {
          if (_userImplementedPlatformClasses.add(superclass)) {
            // Register selectors for all instance methods since these might
            // be called on user classes from within the platform
            // implementation.
            superclass.forEachLocalMember((MemberElement element) {
              if (element.isConstructor || element.isStatic) return;

              FunctionElement function = element.asFunctionElement();
              element.computeType(resolution);
              Selector selector = new Selector.fromElement(element);
              registerUse(
                  new DynamicUse(selector, null));
            });
          }
        }
      }
    }
  }

  @override
  bool enableDeferredLoadingIfSupported(Spannable node, Registry registry) {
    // TODO(sigurdm): Implement deferred loading for dart2dart.
    reporter.reportWarningMessage(
        node, MessageKind.DEFERRED_LIBRARY_DART_2_DART);
    return false;
  }

  @override
  Uri resolvePatchUri(String libraryName, Uri) {
    // Dart2dart does not use patches.
    return null;
  }
}

class DartImpactTransformer extends ImpactTransformer {
  final DartBackend backend;

  DartImpactTransformer(this.backend);

  @override
  WorldImpact transformResolutionImpact(ResolutionImpact worldImpact) {
    TransformedWorldImpact transformed =
        new TransformedWorldImpact(worldImpact);
    for (TypeUse typeUse in worldImpact.typeUses) {
      if (typeUse.kind == TypeUseKind.TYPE_LITERAL &&
          typeUse.type.isInterfaceType) {
        backend.usedTypeLiterals.add(typeUse.type.element);
      }
      if (typeUse.kind == TypeUseKind.INSTANTIATION) {
        backend.registerPlatformMembers(typeUse.type,
            registerUse: transformed.registerDynamicUse);
      }
    }
    return transformed;
  }
}

class EmitterUnparser extends Unparser {
  final Map<Node, String> renames;

  EmitterUnparser(this.renames, {bool minify, bool stripTypes})
      : super(minify: minify, stripTypes: stripTypes);

  visit(Node node) {
    if (node != null && renames.containsKey(node)) {
      write(renames[node]);
    } else {
      super.visit(node);
    }
  }

  unparseSendReceiver(Send node, {bool spacesNeeded: false}) {
    // TODO(smok): Remove ugly hack for library prefices.
    if (node.receiver != null && renames[node.receiver] == '') return;
    super.unparseSendReceiver(node, spacesNeeded: spacesNeeded);
  }

  unparseFunctionName(Node name) {
    if (name != null && renames.containsKey(name)) {
      write(renames[name]);
    } else {
      super.unparseFunctionName(name);
    }
  }
}


/**
 * Some elements are not recorded by resolver now,
 * for example, typedefs or classes which are only
 * used in signatures, as/is operators or in super clauses
 * (just to name a few).  Retraverse AST to pick those up.
 */
class ReferencedElementCollector extends Visitor {
  final DiagnosticReporter reporter;
  final Element element;
  final ElementAst elementAst;
  final newTypedefElementCallback;
  final newClassElementCallback;

  ReferencedElementCollector(this.reporter,
                             this.element,
                             this.elementAst,
                             this.newTypedefElementCallback,
                             this.newClassElementCallback);

  visitNode(Node node) {
    node.visitChildren(this);
  }

  visitTypeAnnotation(TypeAnnotation typeAnnotation) {
    TreeElements treeElements = elementAst.treeElements;
    final DartType type = treeElements.getType(typeAnnotation);
    assert(invariant(typeAnnotation, type != null,
        message: "Missing type for type annotation: $treeElements."));
    if (type.isTypedef) newTypedefElementCallback(type.element);
    if (type.isInterfaceType) newClassElementCallback(type.element);
    typeAnnotation.visitChildren(this);
  }

  void collect() {
    reporter.withCurrentElement(element, () {
      elementAst.ast.accept(this);
    });
  }
}

Comparator compareBy(f) => (x, y) => f(x).compareTo(f(y));

List sorted(Iterable l, comparison) {
  final result = new List.from(l);
  result.sort(comparison);
  return result;
}

compareElements(e0, e1) {
  int result = compareBy((e) => e.library.canonicalUri.toString())(e0, e1);
  if (result != 0) return result;
  return compareBy((e) => e.position.charOffset)(e0, e1);
}

/// [ConstantCompilerTask] for compilation of constants for the Dart backend.
///
/// Since this task needs no distinction between frontend and backend constants
/// it also serves as the [BackendConstantEnvironment].
class DartConstantTask extends ConstantCompilerTask
    implements BackendConstantEnvironment {
  final DartConstantCompiler constantCompiler;

  DartConstantTask(Compiler compiler)
    : this.constantCompiler = new DartConstantCompiler(compiler),
      super(compiler);

  String get name => 'ConstantHandler';

  @override
  ConstantSystem get constantSystem => constantCompiler.constantSystem;

  @override
  ConstantValue getConstantValue(ConstantExpression expression) {
    return constantCompiler.getConstantValue(expression);
  }

  @override
  ConstantValue getConstantValueForVariable(VariableElement element) {
    return constantCompiler.getConstantValueForVariable(element);
  }

  @override
  ConstantExpression getConstantForVariable(VariableElement element) {
    return constantCompiler.getConstantForVariable(element);
  }

  @override
  ConstantExpression getConstantForNode(Node node, TreeElements elements) {
    return constantCompiler.getConstantForNode(node, elements);
  }

  @override
  ConstantValue getConstantValueForNode(Node node, TreeElements elements) {
    return getConstantValue(
        constantCompiler.getConstantForNode(node, elements));
  }

  @override
  ConstantValue getConstantValueForMetadata(MetadataAnnotation metadata) {
    return getConstantValue(metadata.constant);
  }

  @override
  ConstantExpression compileConstant(VariableElement element) {
    return measure(() {
      return constantCompiler.compileConstant(element);
    });
  }

  @override
  void evaluate(ConstantExpression constant) {
    return measure(() {
      return constantCompiler.evaluate(constant);
    });
  }

  void compileVariable(VariableElement element) {
    measure(() {
      constantCompiler.compileVariable(element);
    });
  }

  @override
  ConstantExpression compileNode(
      Node node,
      TreeElements elements,
      {bool enforceConst: true}) {
    return measure(() {
      return constantCompiler.compileNodeWithDefinitions(node, elements,
          isConst: enforceConst);
    });
  }

  @override
  ConstantExpression compileMetadata(
      MetadataAnnotation metadata,
      Node node,
      TreeElements elements) {
    return measure(() {
      return constantCompiler.compileMetadata(metadata, node, elements);
    });
  }

  // TODO(johnniwinther): Remove this when values are computed from the
  // expressions.
  @override
  void copyConstantValues(DartConstantTask task) {
    constantCompiler.constantValueMap.addAll(
        task.constantCompiler.constantValueMap);
  }
}
