// Copyright (c) 2014, 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 backend_ast_emitter;

import '../tree_ir/tree_ir_nodes.dart' as tree;
import 'backend_ast_nodes.dart';
import '../constants/expressions.dart';
import '../constants/values.dart';
import '../dart_types.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart' as modelx;
import '../universe/universe.dart';
import '../tree/tree.dart' as tree show Modifiers;

/// Translates the dart_tree IR to Dart backend AST.
ExecutableDefinition emit(tree.ExecutableDefinition definition) {
  return new ASTEmitter().emit(definition, new BuilderContext<Statement>());
}

// TODO(johnniwinther): Split into function/block state.
class BuilderContext<T> {
  /// Builder context for the enclosing function, or null if the current
  /// function is not a local function.
  BuilderContext<T> _parent;

  /// Variables to be hoisted at the top of the current function.
  final List<VariableDeclaration> variables = <VariableDeclaration>[];

  /// Maps variables to their name.
  final Map<tree.Variable, String> variableNames;

  /// Maps local constants to their name.
  final Map<VariableElement, String> constantNames =
      <VariableElement, String>{};

  /// Variables that have had their declaration created.
  final Set<tree.Variable> declaredVariables = new Set<tree.Variable>();

  /// Variable names that have already been used. Used to avoid name clashes.
  final Set<String> usedVariableNames;

  /// Statements emitted by the most recent call to [visitStatement].
  List<T> _statementBuffer = <T>[];

  /// The element currently being emitted.
  ExecutableElement currentElement;

  /// Bookkeeping object needed to synthesize a variable declaration.
  final modelx.VariableList variableList
      = new modelx.VariableList(tree.Modifiers.EMPTY);

  /// Input to [visitStatement]. Denotes the statement that will execute next
  /// if the statements produced by [visitStatement] complete normally.
  /// Set to null if control will fall over the end of the method.
  tree.Statement fallthrough = null;

  /// Labels that could not be eliminated using fallthrough.
  final Set<tree.Label> _usedLabels = new Set<tree.Label>();

  final bool inInitializer;

  /// The first dart_tree statement that is not converted to a variable
  /// initializer.
  tree.Statement firstStatement;

  BuilderContext() : usedVariableNames = new Set<String>(),
                     inInitializer = false,
                     variableNames = <tree.Variable, String>{};

  BuilderContext.inner(BuilderContext<T> parent)
      : this._parent = parent,
        usedVariableNames = parent.usedVariableNames,
        inInitializer = false,
        variableNames = <tree.Variable, String>{};

  BuilderContext.initializer(BuilderContext<T> parent)
      : this._parent = parent,
        usedVariableNames = parent.usedVariableNames,
        inInitializer = true,
        variableNames =
            new Map<tree.Variable, String>.from(parent.variableNames);

  // TODO(johnniwinther): Fully encapsulate handling of parameter, variable
  // and local funciton declarations.
  void addDeclaration(tree.Variable variable, [Expression initializer]) {
    assert(!declaredVariables.contains(variable));
    String name = getVariableName(variable);
    VariableDeclaration decl = new VariableDeclaration(name, initializer);
    decl.element = variable.element;
    declaredVariables.add(variable);
    variables.add(decl);
  }

  /// Generates a name for the given variable and synthesizes an element for it,
  /// if necessary.
  String getVariableName(tree.Variable variable) {
    // If the variable belongs to an enclosing function, ask the parent emitter
    // for the variable name.
    if (!inInitializer && variable.host != currentElement) {
      return _parent.getVariableName(variable);
    }

    // Get the name if we already have one.
    String name = variableNames[variable];
    if (name != null) {
      return name;
    }

    // Synthesize a variable name that isn't used elsewhere.
    // The [usedVariableNames] set is shared between nested emitters,
    // so this also prevents clash with variables in an enclosing/inner scope.
    // The renaming phase after codegen will further prefix local variables
    // so they cannot clash with top-level variables or fields.
    String prefix = variable.element == null ? 'v' : variable.element.name;
    int counter = 0;
    name = variable.element == null ? '$prefix$counter' : variable.element.name;
    while (!usedVariableNames.add(name)) {
      ++counter;
      name = '$prefix$counter';
    }
    variableNames[variable] = name;

    // Synthesize an element for the variable
    if (variable.element == null || name != variable.element.name) {
      // TODO(johnniwinther): Replace by synthetic [Entity].
      variable.element = new _SyntheticLocalVariableElement(
          name,
          currentElement,
          variableList);
    }
    return name;
  }

  String getConstantName(VariableElement element) {
    assert(element.kind == ElementKind.VARIABLE);
    if (element.enclosingElement != currentElement) {
      return _parent.getConstantName(element);
    }
    String name = constantNames[element];
    if (name != null) {
      return name;
    }
    String prefix = element.name;
    int counter = 0;
    name = element.name;
    while (!usedVariableNames.add(name)) {
      ++counter;
      name = '$prefix$counter';
    }
    constantNames[element] = name;
    return name;
  }

  List<T> inSubcontext(f(BuilderContext<T> subcontext),
                       {tree.Statement fallthrough}) {
    List<T> savedBuffer = this._statementBuffer;
    tree.Statement savedFallthrough = this.fallthrough;
    List<T> buffer = this._statementBuffer = <T>[];
    if (fallthrough != null) {
      this.fallthrough = fallthrough;
    }
    f(this);
    this.fallthrough = savedFallthrough;
    this._statementBuffer = savedBuffer;
    return buffer;
  }

  /// Removes a trailing "return null" from the current block.
  void removeTrailingReturn(bool isReturnNull(T statement)) {
    if (_statementBuffer.isEmpty) return;
    if (isReturnNull(_statementBuffer.last)) {
      _statementBuffer.removeLast();
    }
  }

  /// Register [label] as used.
  void useLabel(tree.Label label) {
    _usedLabels.add(label);
  }

  /// Remove [label] and return `true` if it was used.
  bool removeUsedLabel(tree.Label label) {
    return _usedLabels.remove(label);
  }

  /// Add [statement] to the current block.
  void addStatement(T statement) {
    _statementBuffer.add(statement);
  }

  /// The statements in the current block.
  Iterable<T> get statements => _statementBuffer;
}


/// Translates the dart_tree IR to Dart backend AST.
/// An instance of this class should only be used once; a fresh emitter
/// must be created for each function to be emitted.
class ASTEmitter
    extends tree.Visitor1<dynamic, Expression, BuilderContext<Statement>> {

  ExecutableDefinition emit(tree.ExecutableDefinition definition,
                            BuilderContext<Statement> context) {
    if (definition is tree.FieldDefinition) {
      return emitField(definition, context);
    } else if (definition is tree.ConstructorDefinition) {
      return emitConstructor(definition, context);
    }
    assert(definition is tree.FunctionDefinition);
    return emitFunction(definition, context);
  }

  FieldDefinition emitField(tree.FieldDefinition definition,
                            BuilderContext<Statement> context) {
    context.currentElement = definition.element;
    Expression initializer;
    if (definition.hasInitializer) {
      visitStatement(definition.body, context);
      List<Statement> bodyParts;
      for (tree.Variable variable in context.variableNames.keys) {
        if (!context.declaredVariables.contains(variable)) {
          context.addDeclaration(variable);
        }
      }
      if (context.variables.length > 0) {
        bodyParts = new List<Statement>();
        bodyParts.add(new VariableDeclarations(context.variables));
        bodyParts.addAll(context.statements);
      } else {
        bodyParts = context.statements;
      }
      initializer = ensureExpression(bodyParts);
    }

    return new FieldDefinition(definition.element, initializer);
  }

  /// Returns an expression that will evaluate all of [bodyParts].
  /// If [bodyParts] is a single [Return] return its value.
  /// Otherwise wrap the body-parts in an immediately invoked closure.
  Expression ensureExpression(List<Statement> bodyParts) {
    if (bodyParts.length == 1) {
      Statement onlyStatement = bodyParts.single;
      if (onlyStatement is Return) {
        return onlyStatement.expression;
      }
    }
    Statement body = new Block(bodyParts);
    FunctionExpression function =
        new FunctionExpression(new Parameters([]), body);
    function.element = null;
    return new CallFunction(function, []);
  }

  bool _recognizeTrailingReturn(Statement statement) {
    if (statement is Return) {
      Expression expr = statement.expression;
      if (expr == null || expr is Literal && expr.value.isNull) {
        return true;
      }
    }
    return false;
  }

  FunctionExpression emitConstructor(tree.ConstructorDefinition definition,
                                     BuilderContext<Statement> context) {
    context.currentElement = definition.element;

    Parameters parameters = emitRootParameters(definition, context);

    // Declare parameters.
    for (tree.Variable param in definition.parameters) {
      context.variableNames[param] = param.element.name;
      context.usedVariableNames.add(param.element.name);
      context.declaredVariables.add(param);
    }

    List<Expression> initializers;
    Statement body;

    if (!definition.isAbstract) {
      initializers =
          definition.initializers.map((tree.Initializer initializer) {
        return visitExpression(initializer, context);
      }).toList();

      context.firstStatement = definition.body;
      visitStatement(definition.body, context);
      context.removeTrailingReturn(_recognizeTrailingReturn);

      // Some of the variable declarations have already been added
      // if their first assignment could be pulled into the initializer.
      // Add the remaining variable declarations now.
      for (tree.Variable variable in context.variableNames.keys) {
        if (!context.declaredVariables.contains(variable)) {
          context.addDeclaration(variable);
        }
      }

      // Add constant declarations.
      List<VariableDeclaration> constants = <VariableDeclaration>[];
      for (ConstDeclaration constDecl in definition.localConstants) {
        if (!context.constantNames.containsKey(constDecl.element)) {
          continue; // Discard unused constants declarations.
        }
        String name = context.getConstantName(constDecl.element);
        Expression value =
            ConstantEmitter.createExpression(constDecl.expression, context);
        VariableDeclaration decl = new VariableDeclaration(name, value);
        decl.element = constDecl.element;
        constants.add(decl);
      }

      List<Statement> bodyParts = [];
      if (constants.length > 0) {
        bodyParts.add(new VariableDeclarations(constants, isConst: true));
      }
      if (context.variables.length > 0) {
        bodyParts.add(new VariableDeclarations(context.variables));
      }
      bodyParts.addAll(context.statements);

      body = new Block(bodyParts);

    }
    FunctionType functionType = context.currentElement.type;

    return new ConstructorDefinition(
        parameters,
        body,
        initializers,
        context.currentElement.name, definition.element.isConst)
        ..element = context.currentElement;
  }

  FunctionExpression emitFunction(tree.FunctionDefinition definition,
                                  BuilderContext<Statement> context) {
    context.currentElement = definition.element;

    Parameters parameters = emitRootParameters(definition, context);

    // Declare parameters.
    for (tree.Variable param in definition.parameters) {
      context.variableNames[param] = param.element.name;
      context.usedVariableNames.add(param.element.name);
      context.declaredVariables.add(param);
    }

    Statement body;
    if (definition.isAbstract) {
      body = new EmptyStatement();
    } else {
      context.firstStatement = definition.body;
      visitStatement(definition.body, context);
      context.removeTrailingReturn(_recognizeTrailingReturn);

      // Some of the variable declarations have already been added
      // if their first assignment could be pulled into the initializer.
      // Add the remaining variable declarations now.
      for (tree.Variable variable in context.variableNames.keys) {
        if (!context.declaredVariables.contains(variable)) {
          context.addDeclaration(variable);
        }
      }

      // Add constant declarations.
      List<VariableDeclaration> constants = <VariableDeclaration>[];
      for (ConstDeclaration constDecl in definition.localConstants) {
        if (!context.constantNames.containsKey(constDecl.element)) {
          continue; // Discard unused constants declarations.
        }
        String name = context.getConstantName(constDecl.element);
        Expression value =
            ConstantEmitter.createExpression(constDecl.expression, context);
        VariableDeclaration decl = new VariableDeclaration(name, value);
        decl.element = constDecl.element;
        constants.add(decl);
      }

      List<Statement> bodyParts = [];
      if (constants.length > 0) {
        bodyParts.add(new VariableDeclarations(constants, isConst: true));
      }
      if (context.variables.length > 0) {
        bodyParts.add(new VariableDeclarations(context.variables));
      }
      bodyParts.addAll(context.statements);

      body = new Block(bodyParts);
    }
    FunctionType functionType = context.currentElement.type;

    return new FunctionExpression(
        parameters,
        body,
        name: context.currentElement.name,
        returnType: TypeGenerator.createOptionalType(functionType.returnType),
        isGetter: context.currentElement.isGetter,
        isSetter: context.currentElement.isSetter)
        ..element = context.currentElement;
  }

  /// Emits parameters that are not nested inside other parameters.
  /// Root parameters can have default values, while inner parameters cannot.
  Parameters emitRootParameters(tree.FunctionDefinition function,
                                BuilderContext<Statement> context) {
    FunctionType functionType = function.element.type;
    List<Parameter> required = TypeGenerator.createParameters(
        functionType.parameterTypes,
        context: context,
        elements: function.parameters.map((p) => p.element));
    bool optionalParametersAreNamed = !functionType.namedParameters.isEmpty;
    List<Parameter> optional = TypeGenerator.createParameters(
        optionalParametersAreNamed
            ? functionType.namedParameterTypes
            : functionType.optionalParameterTypes,
        context: context,
        defaultValues: function.defaultParameterValues,
        elements: function.parameters.skip(required.length)
            .map((p) => p.element));
    return new Parameters(required, optional, optionalParametersAreNamed);
  }

  /// True if the two expressions are a reference to the same variable.
  bool isSameVariable(Receiver e1, Receiver e2) {
    return e1 is Identifier &&
           e2 is Identifier &&
           e1.element is VariableElement &&
           e1.element == e2.element;
  }

  Expression makeAssignment(Expression target, Expression value) {
    // Try to print as compound assignment or increment
    if (value is BinaryOperator && isCompoundableOperator(value.operator)) {
      Receiver leftOperand = value.left;
      Expression rightOperand = value.right;
      bool valid = false;
      if (isSameVariable(target, leftOperand)) {
        valid = true;
      } else if (target is FieldExpression &&
                 leftOperand is FieldExpression &&
                 isSameVariable(target.object, leftOperand.object) &&
                 target.fieldName == leftOperand.fieldName) {
        valid = true;
      } else if (target is IndexExpression &&
                 leftOperand is IndexExpression &&
                 isSameVariable(target.object, leftOperand.object) &&
                 isSameVariable(target.index, leftOperand.index)) {
        valid = true;
      }
      if (valid) {
        if (rightOperand is Literal && rightOperand.value.isOne &&
            (value.operator == '+' || value.operator == '-')) {
          return new Increment.prefix(target, value.operator + value.operator);
        } else {
          return new Assignment(target, value.operator + '=', rightOperand);
        }
      }
    }
    // Fall back to regular assignment
    return new Assignment(target, '=', value);
  }

  Block visitInSubContext(tree.Statement statement,
                          BuilderContext<Statement> context,
                          {tree.Statement fallthrough}) {
    return new Block(context.inSubcontext(
        (BuilderContext<Statement> subcontext) {
      visitStatement(statement, subcontext);
    }, fallthrough: fallthrough));
  }

  void addLabeledStatement(tree.Label label,
                           Statement statement,
                           BuilderContext<Statement> context) {
    if (context.removeUsedLabel(label)) {
      context.addStatement(new LabeledStatement(label.name, statement));
    } else {
      context.addStatement(statement);
    }
  }

  @override
  void visitExpressionStatement(tree.ExpressionStatement stmt,
                                BuilderContext<Statement> context) {
    Expression e = visitExpression(stmt.expression, context);
    context.addStatement(new ExpressionStatement(e));

    visitStatement(stmt.next, context);
  }

  @override
  void visitLabeledStatement(tree.LabeledStatement stmt,
                             BuilderContext<Statement> context) {
    Block block = visitInSubContext(stmt.body, context, fallthrough: stmt.next);
    addLabeledStatement(stmt.label, block, context);

    visitStatement(stmt.next, context);
  }

  bool isNullLiteral(Expression exp) => exp is Literal && exp.value.isNull;

  @override
  void visitAssign(tree.Assign stmt,
                   BuilderContext<Statement> context) {
    // Try to emit a local function declaration. This is useful for functions
    // that may occur in expression context, but could not be inlined anywhere.
    if (stmt.variable.element is FunctionElement &&
        stmt.definition is tree.FunctionExpression &&
        !context.declaredVariables.contains(stmt.variable)) {
      tree.FunctionExpression functionExp = stmt.definition;
      FunctionExpression function =
          makeSubFunction(functionExp.definition, context);
      FunctionDeclaration decl = new FunctionDeclaration(function);
      context.addStatement(decl);
      context.declaredVariables.add(stmt.variable);

      visitStatement(stmt.next, context);
      return;
    }

    bool isFirstOccurrence = (context.variableNames[stmt.variable] == null);
    bool isDeclaredHere = stmt.variable.host == context.currentElement;
    String name = context.getVariableName(stmt.variable);
    Expression definition = visitExpression(stmt.definition, context);

    // Try to pull into initializer.
    if (context.firstStatement == stmt && isFirstOccurrence && isDeclaredHere) {
      if (isNullLiteral(definition)) definition = null;
      context.addDeclaration(stmt.variable, definition);
      context.firstStatement = stmt.next;
      visitStatement(stmt.next, context);
      return;
    }

    // Emit a variable declaration if we are required to do so.
    // This is to ensure that a fresh closure variable is created.
    if (stmt.isDeclaration) {
      assert(isFirstOccurrence);
      assert(isDeclaredHere);
      if (isNullLiteral(definition)) definition = null;
      VariableDeclaration decl = new VariableDeclaration(name, definition)
                                     ..element = stmt.variable.element;
      context.declaredVariables.add(stmt.variable);
      context.addStatement(new VariableDeclarations([decl]));
      visitStatement(stmt.next, context);
      return;
    }

    context.addStatement(new ExpressionStatement(makeAssignment(
        visitVariable(stmt.variable, context),
        definition)));
    visitStatement(stmt.next, context);
  }

  @override
  void visitReturn(tree.Return stmt,
                   BuilderContext<Statement> context) {
    if (context.currentElement.isGenerativeConstructor &&
        !context.inInitializer) {
      assert(() {
        tree.Expression value = stmt.value;
        return value is tree.Constant && value.value.isNull;
      });
      context.addStatement(new Return(null));
    } else {
      Expression inner = visitExpression(stmt.value, context);
      context.addStatement(new Return(inner));
    }
  }

  @override
  void visitBreak(tree.Break stmt,
                  BuilderContext<Statement> context) {
    tree.Statement fall = context.fallthrough;
    if (stmt.target.binding.next == fall) {
      // Fall through to break target
    } else if (fall is tree.Break && fall.target == stmt.target) {
      // Fall through to equivalent break
    } else {
      context.useLabel(stmt.target);
      context.addStatement(new Break(stmt.target.name));
    }
  }

  @override
  void visitContinue(tree.Continue stmt,
                     BuilderContext<Statement> context) {
    tree.Statement fall = context.fallthrough;
    if (stmt.target.binding == fall) {
      // Fall through to continue target
    } else if (fall is tree.Continue && fall.target == stmt.target) {
      // Fall through to equivalent continue
    } else {
      context.useLabel(stmt.target);
      context.addStatement(new Continue(stmt.target.name));
    }
  }

  @override
  void visitIf(tree.If stmt,
               BuilderContext<Statement> context) {
    Expression condition = visitExpression(stmt.condition, context);
    Block thenBlock = visitInSubContext(stmt.thenStatement, context);
    Block elseBlock= visitInSubContext(stmt.elseStatement, context);
    context.addStatement(new If(condition, thenBlock, elseBlock));
  }

  @override
  void visitWhileTrue(tree.WhileTrue stmt,
                      BuilderContext<Statement> context) {
    Block body = visitInSubContext(stmt.body, context, fallthrough: stmt);
    Statement statement =
        new While(new Literal(new TrueConstantValue()), body);
    addLabeledStatement(stmt.label, statement, context);
  }

  @override
  void visitWhileCondition(tree.WhileCondition stmt,
                           BuilderContext<Statement> context) {
    Expression condition = visitExpression(stmt.condition, context);
    Block body = visitInSubContext(stmt.body, context, fallthrough: stmt);
    Statement statement = new While(condition, body);
    addLabeledStatement(stmt.label, statement, context);

    visitStatement(stmt.next, context);
  }

  @override
  Expression visitConstant(tree.Constant exp,
                           BuilderContext<Statement> context) {
    return ConstantEmitter.createExpression(exp.expression, context);
  }

  @override
  Expression visitThis(tree.This exp,
                       BuilderContext<Statement> context) {
    return new This();
  }

  @override
  Expression visitReifyTypeVar(tree.ReifyTypeVar exp,
                               BuilderContext<Statement> context) {
    return new ReifyTypeVar(exp.typeVariable.name)
               ..element = exp.typeVariable;
  }

  List<Expression> visitExpressions(List<tree.Expression> expressions,
                                    BuilderContext<Statement> context) {
    return expressions.map((expression) => visitExpression(expression, context))
        .toList(growable: false);
  }

  @override
  Expression visitLiteralList(tree.LiteralList exp,
                              BuilderContext<Statement> context) {
    return new LiteralList(visitExpressions(exp.values, context),
        typeArgument:
            TypeGenerator.createOptionalType(exp.type.typeArguments.single));
  }

  @override
  Expression visitLiteralMap(tree.LiteralMap exp,
                             BuilderContext<Statement> context) {
    List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate(
        exp.entries.length,
        (i) => new LiteralMapEntry(
            visitExpression(exp.entries[i].key, context),
            visitExpression(exp.entries[i].value, context)));
    List<TypeAnnotation> typeArguments = exp.type.treatAsRaw
        ? null
        : exp.type.typeArguments.map(TypeGenerator.createType)
             .toList(growable: false);
    return new LiteralMap(entries, typeArguments: typeArguments);
  }

  @override
  Expression visitTypeOperator(tree.TypeOperator exp,
                               BuilderContext<Statement> context) {
    return new TypeOperator(visitExpression(exp.receiver, context),
                            exp.operator,
                            TypeGenerator.createType(exp.type));
  }

  List<Argument> emitArguments(List<Expression> arguments,
                               Selector selector) {
    int positionalArgumentCount = selector.positionalArgumentCount;
    List<Argument> result = new List<Argument>.generate(positionalArgumentCount,
        (i) => arguments[i]);
    for (int i = 0; i < selector.namedArgumentCount; ++i) {
      result.add(new NamedArgument(selector.namedArguments[i],
          arguments[positionalArgumentCount + i]));
    }
    return result;
  }

  List<Expression> visitArgumentList(List<tree.Expression> arguments,
                                     BuilderContext context) {
    return arguments
        .map((tree.Expression argument) => visitExpression(argument, context))
        .toList();
  }

  @override
  Expression visitInvokeStatic(tree.InvokeStatic exp,
                               BuilderContext<Statement> context) {
    switch (exp.selector.kind) {
      case SelectorKind.GETTER:
        return new Identifier(exp.target.name)..element = exp.target;

      case SelectorKind.SETTER:
        return new Assignment(
            new Identifier(exp.target.name)..element = exp.target,
            '=',
            visitExpression(exp.arguments[0], context));

      case SelectorKind.CALL:
        return new CallStatic(
            null, exp.target.name,
            emitArguments(visitArgumentList(exp.arguments, context),
                          exp.selector))
            ..element = exp.target;

      default:
        throw "Unexpected selector kind: ${exp.selector.kind}";
    }
  }

  Expression emitMethodCall(tree.Invoke exp, Receiver receiver,
                            BuilderContext<Statement> context) {
    List<Argument> args =
        emitArguments(visitArgumentList(exp.arguments, context), exp.selector);
    switch (exp.selector.kind) {
      case SelectorKind.CALL:
        if (exp.selector.name == "call") {
          return new CallFunction(receiver, args);
        }
        return new CallMethod(receiver, exp.selector.name, args);

      case SelectorKind.OPERATOR:
        if (args.length == 0) {
          String name = exp.selector.name;
          if (name == 'unary-') {
            name = '-';
          }
          return new UnaryOperator(name, receiver);
        }
        return new BinaryOperator(receiver, exp.selector.name, args[0]);

      case SelectorKind.GETTER:
        return new FieldExpression(receiver, exp.selector.name);

      case SelectorKind.SETTER:
        return makeAssignment(
            new FieldExpression(receiver, exp.selector.name),
            args[0]);

      case SelectorKind.INDEX:
        Expression e = new IndexExpression(receiver, args[0]);
        if (args.length == 2) {
          e = makeAssignment(e, args[1]);
        }
        return e;

      default:
        throw "Unexpected selector in InvokeMethod: ${exp.selector.kind}";
    }
  }

  @override
  Expression visitInvokeMethod(tree.InvokeMethod exp,
                               BuilderContext<Statement> context) {
    Expression receiver = visitExpression(exp.receiver, context);
    return emitMethodCall(exp, receiver, context);
  }

  @override
  Expression visitInvokeMethodDirectly(tree.InvokeMethodDirectly exp,
                                       BuilderContext<Statement> context) {
    // When targeting Dart, InvokeMethodDirectly is only used for super calls.
    // The receiver is known to be `this`, and the target method is a method
    // on the super class. So we just translate it as a method call with the
    // super receiver.
    return emitMethodCall(exp, new SuperReceiver(), context);
  }

  @override
  Expression visitInvokeConstructor(tree.InvokeConstructor exp,
                                    BuilderContext<Statement> context) {
    List<Argument> args =
        emitArguments(visitArgumentList(exp.arguments, context), exp.selector);
    FunctionElement constructor = exp.target;
    String name = constructor.name.isEmpty ? null : constructor.name;
    return new CallNew(TypeGenerator.createType(exp.type),
                       args,
                       constructorName: name,
                       isConst: exp.constant != null)
               ..constructor = constructor
               ..dartType = exp.type;
  }

  @override
  Expression visitConcatenateStrings(tree.ConcatenateStrings exp,
                                     BuilderContext<Statement> context) {
    return new StringConcat(visitExpressions(exp.arguments, context));
  }

  @override
  Expression visitConditional(tree.Conditional exp,
                              BuilderContext<Statement> context) {
    return new Conditional(
        visitExpression(exp.condition, context),
        visitExpression(exp.thenExpression, context),
        visitExpression(exp.elseExpression, context));
  }

  @override
  Expression visitLogicalOperator(tree.LogicalOperator exp,
                                  BuilderContext<Statement> context) {
    return new BinaryOperator(visitExpression(exp.left, context),
                              exp.operator,
                              visitExpression(exp.right, context));
  }

  @override
  Expression visitNot(tree.Not exp,
                      BuilderContext<Statement> context) {
    return new UnaryOperator('!', visitExpression(exp.operand, context));
  }

  @override
  Expression visitVariable(tree.Variable exp,
                           BuilderContext<Statement> context) {
    return new Identifier(context.getVariableName(exp))
               ..element = exp.element;
  }

  FunctionExpression makeSubFunction(tree.FunctionDefinition function,
                                     BuilderContext<Statement> context) {
    return emit(function, new BuilderContext<Statement>.inner(context));
  }

  @override
  Expression visitFunctionExpression(tree.FunctionExpression exp,
                                     BuilderContext<Statement> context) {
    return makeSubFunction(exp.definition, context)..name = null;
  }

  @override
  void visitFunctionDeclaration(tree.FunctionDeclaration node,
                                BuilderContext<Statement> context) {
    assert(context.variableNames[node.variable] == null);
    String name = context.getVariableName(node.variable);
    FunctionExpression inner = makeSubFunction(node.definition, context);
    inner.name = name;
    FunctionDeclaration decl = new FunctionDeclaration(inner);
    context.declaredVariables.add(node.variable);
    context.addStatement(decl);
    visitStatement(node.next, context);
  }

  List<Statement> buildInInitializerContext(tree.Statement root,
                                     BuilderContext context) {
    BuilderContext inner = new BuilderContext<Statement>.initializer(context);
    inner.currentElement = context.currentElement;
    visitStatement(root, inner);
    List<Statement> bodyParts;
    for (tree.Variable variable in inner.variableNames.keys) {
      if (!context.declaredVariables.contains(variable)) {
        inner.addDeclaration(variable);
      }
    }
    if (inner.variables.length > 0) {
      bodyParts = new List<Statement>();
      bodyParts.add(new VariableDeclarations(inner.variables));
      bodyParts.addAll(inner.statements);
    } else {
      bodyParts = inner.statements;
    }
    return bodyParts;
  }

  @override
  Expression visitFieldInitializer(tree.FieldInitializer node,
                                   BuilderContext<Statement> context) {
    return new FieldInitializer(node.element,
        ensureExpression(buildInInitializerContext(node.body, context)));
  }

  @override
  Expression visitSuperInitializer(tree.SuperInitializer node,
                                   BuilderContext<Statement> context) {
    List<Argument> arguments = node.arguments.map((tree.Statement argument) {
      return ensureExpression(buildInInitializerContext(argument, context));
    }).toList();
    return new SuperInitializer(node.target,
                                emitArguments(arguments, node.selector));
  }

  @override
  visitGetField(tree.GetField node, arg) => errorUnsupportedNode(node);

  @override
  visitSetField(tree.SetField node, arg) => errorUnsupportedNode(node);

  @override
  visitCreateBox(tree.CreateBox node, arg) => errorUnsupportedNode(node);

  @override
  visitCreateInstance(tree.CreateInstance node, arg) {
    return errorUnsupportedNode(node);
  }

  errorUnsupportedNode(tree.JsSpecificNode node) {
    throw '$node not supported by dart backend';
  }
}

class TypeGenerator {

  /// TODO(johnniwinther): Remove this when issue 21283 has been resolved.
  static int pseudoNameCounter = 0;

  static Parameter emitParameter(DartType type,
                                 BuilderContext<Statement> context,
                                 {String name,
                                  Element element,
                                  ConstantExpression defaultValue}) {
    if (name == null && element != null) {
      name = element.name;
    }
    if (name == null) {
      name = '_${pseudoNameCounter++}';
    }
    Parameter parameter;
    if (type.isFunctionType) {
      FunctionType functionType = type;
      TypeAnnotation returnType = createOptionalType(functionType.returnType);
      Parameters innerParameters =
          createParametersFromType(functionType);
      parameter = new Parameter.function(name, returnType, innerParameters);
    } else {
      TypeAnnotation typeAnnotation = createOptionalType(type);
      parameter = new Parameter(name, type: typeAnnotation);
    }
    parameter.element = element;
    if (defaultValue != null && !defaultValue.value.isNull) {
      parameter.defaultValue =
          ConstantEmitter.createExpression(defaultValue, context);
    }
    return parameter;
  }

  static Parameters createParametersFromType(FunctionType functionType) {
    pseudoNameCounter = 0;
    if (functionType.namedParameters.isEmpty) {
      return new Parameters(
          createParameters(functionType.parameterTypes),
          createParameters(functionType.optionalParameterTypes),
          false);
    } else {
      return new Parameters(
          createParameters(functionType.parameterTypes),
          createParameters(functionType.namedParameterTypes,
                         names: functionType.namedParameters),
          true);
    }
  }

  static List<Parameter> createParameters(
      Iterable<DartType> parameterTypes,
      {BuilderContext<Statement> context,
       Iterable<String> names: const <String>[],
       Iterable<ConstantExpression> defaultValues: const <ConstantExpression>[],
       Iterable<Element> elements: const <Element>[]}) {
    Iterator<String> name = names.iterator;
    Iterator<ConstantExpression> defaultValue = defaultValues.iterator;
    Iterator<Element> element = elements.iterator;
    return parameterTypes.map((DartType type) {
      name.moveNext();
      defaultValue.moveNext();
      element.moveNext();
      return emitParameter(type, context,
                           name: name.current,
                           defaultValue: defaultValue.current,
                           element: element.current);
    }).toList();
  }

  /// Like [createTypeAnnotation] except the dynamic type is converted to null.
  static TypeAnnotation createOptionalType(DartType type) {
    if (type.treatAsDynamic) {
      return null;
    } else {
      return createType(type);
    }
  }

  /// Creates the [TypeAnnotation] for a [type] that is not function type.
  static TypeAnnotation createType(DartType type) {
    if (type is GenericType) {
      if (type.treatAsRaw) {
        return new TypeAnnotation(type.element.name)..dartType = type;
      }
      return new TypeAnnotation(
          type.element.name,
          type.typeArguments.map(createType).toList(growable:false))
          ..dartType = type;
    } else if (type is VoidType) {
      return new TypeAnnotation('void')
          ..dartType = type;
    } else if (type is TypeVariableType) {
      return new TypeAnnotation(type.name)
          ..dartType = type;
    } else if (type is DynamicType) {
      return new TypeAnnotation("dynamic")
          ..dartType = type;
    } else if (type is MalformedType) {
      return new TypeAnnotation(type.name)
          ..dartType = type;
    } else {
      throw "Unsupported type annotation: $type";
    }
  }

}


class ConstantEmitter
    extends ConstantExpressionVisitor<BuilderContext<Statement>, Expression> {
  const ConstantEmitter();

  /// Creates the [Expression] for the constant [exp].
  static Expression createExpression(ConstantExpression exp,
                                     BuilderContext<Statement> context) {
    return const ConstantEmitter().visit(exp, context);
  }

  Expression handlePrimitiveConstant(PrimitiveConstantValue value) {
    // Num constants may be negative, while literals must be non-negative:
    // Literals are non-negative in the specification, and a negated literal
    // parses as a call to unary `-`. The AST unparser assumes literals are
    // non-negative and relies on this to avoid incorrectly generating `--`,
    // the predecrement operator.
    // Translate such constants into their positive value wrapped by
    // the unary minus operator.
    if (value.isNum) {
      NumConstantValue numConstant = value;
      if (numConstant.primitiveValue.isNegative) {
        return negatedLiteral(numConstant);
      }
    }
    return new Literal(value);
  }

  List<Expression> visitExpressions(List<ConstantExpression> expressions,
                                    BuilderContext<Statement> context) {
    return expressions.map((expression) => visit(expression, context))
        .toList(growable: false);
  }

  @override
  Expression visitPrimitive(PrimitiveConstantExpression exp,
                            BuilderContext<Statement> context) {
    return handlePrimitiveConstant(exp.value);
  }

  /// Given a negative num constant, returns the corresponding positive
  /// literal wrapped by a unary minus operator.
  Expression negatedLiteral(NumConstantValue constant) {
    assert(constant.primitiveValue.isNegative);
    NumConstantValue positiveConstant;
    if (constant.isInt) {
      positiveConstant = new IntConstantValue(-constant.primitiveValue);
    } else if (constant.isDouble) {
      positiveConstant = new DoubleConstantValue(-constant.primitiveValue);
    } else {
      throw "Unexpected type of NumConstant: $constant";
    }
    return new UnaryOperator('-', new Literal(positiveConstant));
  }

  @override
  Expression visitList(ListConstantExpression exp,
                       BuilderContext<Statement> context) {
    return new LiteralList(
        visitExpressions(exp.values, context),
        isConst: true,
        typeArgument:
            TypeGenerator.createOptionalType(exp.type.typeArguments.single));
  }

  @override
  Expression visitMap(MapConstantExpression exp,
                      BuilderContext<Statement> context) {
    List<LiteralMapEntry> entries = new List<LiteralMapEntry>.generate(
        exp.values.length,
        (i) => new LiteralMapEntry(visit(exp.keys[i], context),
                                   visit(exp.values[i], context)));
    List<TypeAnnotation> typeArguments = exp.type.treatAsRaw
        ? null
        : exp.type.typeArguments.map(TypeGenerator.createType).toList();
    return new LiteralMap(entries, isConst: true, typeArguments: typeArguments);
  }

  @override
  Expression visitConstructed(ConstructedConstantExpresssion exp,
                              BuilderContext<Statement> context) {
    int positionalArgumentCount = exp.selector.positionalArgumentCount;
    List<Argument> args = new List<Argument>.generate(
        positionalArgumentCount,
        (i) => visit(exp.arguments[i], context));
    for (int i = 0; i < exp.selector.namedArgumentCount; ++i) {
      args.add(new NamedArgument(exp.selector.namedArguments[i],
          visit(exp.arguments[positionalArgumentCount + i], context)));
    }

    FunctionElement constructor = exp.target;
    String name = constructor.name.isEmpty ? null : constructor.name;
    return new CallNew(TypeGenerator.createType(exp.type),
                       args,
                       constructorName: name,
                       isConst: true)
               ..constructor = constructor
               ..dartType = exp.type;
  }

  @override
  Expression visitConcatenate(ConcatenateConstantExpression exp,
                              BuilderContext<Statement> context) {

    return new StringConcat(visitExpressions(exp.arguments, context));
  }

  @override
  Expression visitSymbol(SymbolConstantExpression exp,
                         BuilderContext<Statement> context) {
    return new LiteralSymbol(exp.name);
  }

  @override
  Expression visitType(TypeConstantExpression exp,
                       BuilderContext<Statement> context) {
    DartType type = exp.type;
    return new LiteralType(type.name)
               ..type = type;
  }

  @override
  Expression visitVariable(VariableConstantExpression exp,
                           BuilderContext<Statement> context) {
    Element element = exp.element;
    if (element.kind != ElementKind.VARIABLE) {
      return new Identifier(element.name)..element = element;
    }
    String name = context.getConstantName(element);
    return new Identifier(name)
               ..element = element;
  }

  @override
  Expression visitFunction(FunctionConstantExpression exp,
                           BuilderContext<Statement> context) {
    return new Identifier(exp.element.name)
               ..element = exp.element;
  }

  @override
  Expression visitBinary(BinaryConstantExpression exp,
                         BuilderContext<Statement> context) {
    return handlePrimitiveConstant(exp.value);
  }

  @override
  Expression visitConditional(ConditionalConstantExpression exp,
                              BuilderContext<Statement> context) {
    if (exp.condition.value.isTrue) {
      return exp.trueExp.accept(this);
    } else {
      return exp.falseExp.accept(this);
    }
  }

  @override
  Expression visitUnary(UnaryConstantExpression exp,
                        BuilderContext<Statement> context) {
    return handlePrimitiveConstant(exp.value);
  }
}

/// Moves function parameters into a separate variable if one of its uses is
/// shadowed by an inner function parameter.
/// This artifact is necessary because function parameters cannot be renamed.
class UnshadowParameters extends tree.RecursiveVisitor {

  /// Maps parameter names to their bindings.
  Map<String, tree.Variable> environment = <String, tree.Variable>{};

  /// Parameters that are currently shadowed by another parameter.
  Set<tree.Variable> shadowedParameters = new Set<tree.Variable>();

  /// Parameters that are used in a context where it is shadowed.
  Set<tree.Variable> hasShadowedUse = new Set<tree.Variable>();

  void unshadow(tree.ExecutableDefinition definition) {
    // Fields have no parameters.
    if (definition is tree.FieldDefinition) return;
    visitFunctionDefinition(definition);
  }

  visitFunctionDefinition(tree.FunctionDefinition definition) {
    if (definition.isAbstract) return;
    var oldShadow = shadowedParameters;
    var oldEnvironment = environment;
    environment = new Map<String, tree.Variable>.from(environment);
    shadowedParameters = new Set<tree.Variable>.from(shadowedParameters);
    for (tree.Variable param in definition.parameters) {
      tree.Variable oldVariable = environment[param.element.name];
      if (oldVariable != null) {
        shadowedParameters.add(oldVariable);
      }
      environment[param.element.name] = param;
    }
    visitStatement(definition.body);
    environment = oldEnvironment;
    shadowedParameters = oldShadow;

    for (int i=0; i<definition.parameters.length; i++) {
      tree.Variable param = definition.parameters[i];
      if (hasShadowedUse.remove(param)) {
        tree.Variable newParam = new tree.Variable(definition.element,
            param.element);
        definition.parameters[i] = newParam;
        definition.body = new tree.Assign(param, newParam, definition.body);
        newParam.writeCount = 1; // Being a parameter counts as a write.
      }
    }
  }

  visitVariable(tree.Variable variable) {
    if (shadowedParameters.contains(variable)) {
      hasShadowedUse.add(variable);
    }
  }

}

// TODO(johnniwinther): Remove this when the dart `backend_ast` does not need
// [Element] for entities.
class _SyntheticLocalVariableElement extends modelx.VariableElementX
    implements LocalVariableElement {

  _SyntheticLocalVariableElement(String name,
                                 ExecutableElement enclosingElement,
                                 modelx.VariableList variables)
      : super(name, ElementKind.VARIABLE, enclosingElement, variables, null);

  ExecutableElement get executableContext => enclosingElement;

  ExecutableElement get memberContext => executableContext.memberContext;

  bool get isLocal => true;

  LibraryElement get implementationLibrary => enclosingElement.library;
}
