// Copyright (c) 2016, 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 fasta.body_builder;

import '../parser/parser.dart' show FormalParameterType, optional;

import '../parser/error_kind.dart' show ErrorKind;

import '../parser/identifier_context.dart' show IdentifierContext;

import 'package:kernel/ast.dart';

import 'package:kernel/clone.dart' show CloneVisitor;

import 'package:kernel/transformations/flags.dart' show TransformerFlag;

import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;

import 'package:kernel/core_types.dart' show CoreTypes;

import '../parser/dart_vm_native.dart' show skipNativeClause;

import '../scanner/token.dart'
    show BeginGroupToken, Token, isBinaryOperator, isMinusOperator;

import '../errors.dart' show formatUnexpected, internalError;

import '../source/scope_listener.dart'
    show JumpTargetKind, NullValue, ScopeListener;

import '../builder/scope.dart' show AccessErrorBuilder, AmbiguousBuilder, Scope;

import '../source/outline_builder.dart' show asyncMarkerFromTokens;

import 'builder_accessors.dart';

import 'frontend_accessors.dart' show buildIsNull, makeBinary, makeLet;

import 'builder_accessors.dart' as builder_accessors
    show throwNoSuchMethodError;

import '../quote.dart'
    show
        Quote,
        analyzeQuote,
        unescape,
        unescapeFirstStringPart,
        unescapeLastStringPart,
        unescapeString;

import '../modifier.dart' show Modifier, constMask, finalMask;

import 'redirecting_factory_body.dart' show getRedirectionTarget;

import 'kernel_builder.dart';

final Name callName = new Name("call");

final Name plusName = new Name("+");

final Name minusName = new Name("-");

final Name multiplyName = new Name("*");

final Name divisionName = new Name("/");

final Name percentName = new Name("%");

final Name ampersandName = new Name("&");

final Name leftShiftName = new Name("<<");

final Name rightShiftName = new Name(">>");

final Name caretName = new Name("^");

final Name barName = new Name("|");

final Name mustacheName = new Name("~/");

final Name indexGetName = new Name("[]");

final Name indexSetName = new Name("[]=");

class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
  final KernelLibraryBuilder library;

  final MemberBuilder member;

  final KernelClassBuilder classBuilder;

  final ClassHierarchy hierarchy;

  @override
  final CoreTypes coreTypes;

  final bool isInstanceMember;

  final Map<String, FieldInitializer> fieldInitializers =
      <String, FieldInitializer>{};

  final Scope enclosingScope;

  final bool isDartLibrary;

  @override
  final Uri uri;

  Scope formalParameterScope;

  bool isFirstIdentifier = false;

  bool inInitializer = false;

  bool inCatchClause = false;

  int functionNestingLevel = 0;

  Statement compileTimeErrorInTry;

  Statement compileTimeErrorInLoopOrSwitch;

  Scope switchScope;

  CloneVisitor cloner;

  BodyBuilder(
      KernelLibraryBuilder library,
      this.member,
      Scope scope,
      this.formalParameterScope,
      this.hierarchy,
      this.coreTypes,
      this.classBuilder,
      this.isInstanceMember,
      this.uri)
      : enclosingScope = scope,
        library = library,
        isDartLibrary = library.uri.scheme == "dart",
        super(scope);

  bool get hasParserError => recoverableErrors.isNotEmpty;

  bool get inConstructor {
    return functionNestingLevel == 0 && member is KernelConstructorBuilder;
  }

  bool get isInstanceContext {
    return isInstanceMember || member is KernelConstructorBuilder;
  }

  @override
  void push(Object node) {
    isFirstIdentifier = false;
    inInitializer = false;
    super.push(node);
  }

  Expression popForValue() => toValue(pop());

  Expression popForEffect() => toEffect(pop());

  Expression popForValueIfNotNull(Object value) {
    return value == null ? null : popForValue();
  }

  @override
  Expression toValue(Object node) {
    if (node is UnresolvedIdentifier) {
      if (isDartLibrary &&
          node.name.name == "main" &&
          library.uri.path == "_builtin" &&
          member?.name == "_getMainClosure") {
        // TODO(ahe): https://github.com/dart-lang/sdk/issues/28989
        return new NullLiteral()..fileOffset = node.fileOffset;
      }
      return throwNoSuchMethodError(
          node.name.name, new Arguments.empty(), node.fileOffset,
          isGetter: true);
    } else if (node is BuilderAccessor) {
      return node.buildSimpleRead();
    } else if (node is TypeVariableBuilder) {
      TypeParameterType type = node.buildTypesWithBuiltArguments(library, null);
      if (!isInstanceContext && type.parameter.parent is Class) {
        return buildCompileTimeError(
            "Type variables can only be used in instance methods.");
      } else {
        return new TypeLiteral(type);
      }
    } else if (node is TypeDeclarationBuilder) {
      return new TypeLiteral(node.buildTypesWithBuiltArguments(library, null));
    } else if (node is KernelTypeBuilder) {
      return new TypeLiteral(node.build(library));
    } else if (node is Expression) {
      return node;
    } else if (node is PrefixBuilder) {
      return buildCompileTimeError("A library can't be used as an expression.");
    } else {
      return internalError("Unhandled: ${node.runtimeType}");
    }
  }

  Expression toEffect(Object node) {
    if (node is BuilderAccessor) return node.buildForEffect();
    return toValue(node);
  }

  List<Expression> popListForValue(int n) {
    List<Expression> list =
        new List<Expression>.filled(n, null, growable: true);
    for (int i = n - 1; i >= 0; i--) {
      list[i] = popForValue();
    }
    return list;
  }

  List<Expression> popListForEffect(int n) {
    List<Expression> list =
        new List<Expression>.filled(n, null, growable: true);
    for (int i = n - 1; i >= 0; i--) {
      list[i] = popForEffect();
    }
    return list;
  }

  Block popBlock(int count) {
    List<dynamic /*Statement | List<Statement>*/ > statements =
        popList(count) ?? <Statement>[];
    List<Statement> copy;
    for (int i = 0; i < statements.length; i++) {
      var statement = statements[i];
      if (statement is List) {
        copy ??= new List<Statement>.from(statements.getRange(0, i));
        // TODO(sigmund): remove this assignment (issue #28651)
        Iterable subStatements = statement;
        copy.addAll(subStatements);
      } else if (copy != null) {
        copy.add(statement);
      }
    }
    return new Block(copy ?? statements);
  }

  Statement popStatementIfNotNull(Object value) {
    return value == null ? null : popStatement();
  }

  Statement popStatement() {
    var statement = pop();
    if (statement is List) {
      return new Block(new List<Statement>.from(statement));
    } else {
      return statement;
    }
  }

  void ignore(Unhandled value) {
    pop();
  }

  void enterSwitchScope() {
    push(switchScope ?? NullValue.SwitchScope);
    switchScope = scope;
  }

  void exitSwitchScope() {
    Scope outerSwitchScope = pop();
    if (switchScope.unclaimedForwardDeclarations != null) {
      switchScope.unclaimedForwardDeclarations
          .forEach((String name, Builder builder) {
        if (outerSwitchScope == null) {
          addCompileTimeError(-1, "Label not found: '$name'.");
        } else {
          outerSwitchScope.forwardDeclareLabel(name, builder);
        }
      });
    }
    switchScope = outerSwitchScope;
  }

  @override
  JumpTarget createJumpTarget(JumpTargetKind kind, int charOffset) {
    return new JumpTarget(kind, functionNestingLevel, member, charOffset);
  }

  @override
  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
    debugEvent("Metadata");
    pop(); // Arguments.
    popIfNotNull(periodBeforeName); // Postfix.
    pop(); // Type arguments.
    pop(); // Expression or type name (depends on arguments).
    // TODO(ahe): Implement metadata on local declarations.
  }

  @override
  void endMetadataStar(int count, bool forParameter) {
    debugEvent("MetadataStar");
    push(NullValue.Metadata);
  }

  @override
  void endTopLevelFields(int count, Token beginToken, Token endToken) {
    debugEvent("TopLevelFields");
    doFields(count);
    // There's no metadata here because of a slight assymetry between
    // [parseTopLevelMember] and [parseMember]. This assymetry leads to
    // DietListener discarding top-level member metadata.
  }

  @override
  void endFields(
      int count, Token covariantKeyword, Token beginToken, Token endToken) {
    debugEvent("Fields");
    doFields(count);
    pop(); // Metadata.
  }

  void doFields(int count) {
    for (int i = 0; i < count; i++) {
      Expression initializer = pop();
      Identifier identifier = pop();
      if (initializer != null) {
        String name = identifier.name;
        FieldBuilder field;
        if (classBuilder != null) {
          field = classBuilder.members[name];
        } else {
          field = library.members[name];
        }
        if (field.next != null) {
          // TODO(ahe): This can happen, for example, if a final field is
          // combined with a setter.
          internalError(
              "Unhandled: '${field.name}' has more than one declaration.");
        }
        field.initializer = initializer;
      }
    }
    pop(); // Type.
    pop(); // Modifiers.
  }

  @override
  void endMember() {
    debugEvent("Member");
    checkEmpty(-1);
  }

  @override
  void endBlockFunctionBody(int count, Token beginToken, Token endToken) {
    debugEvent("BlockFunctionBody");
    if (beginToken == null) {
      assert(count == 0);
      push(NullValue.Block);
    } else {
      Block block = popBlock(count);
      exitLocalScope();
      push(block);
    }
  }

  @override
  void prepareInitializers() {
    scope = formalParameterScope;
    assert(fieldInitializers.isEmpty);
    final member = this.member;
    if (member is KernelConstructorBuilder) {
      Constructor constructor = member.constructor;
      classBuilder.members.forEach((String name, Builder builder) {
        if (builder is KernelFieldBuilder && builder.isInstanceMember) {
          // TODO(ahe): Compute initializers (as in `field = initializer`).
          fieldInitializers[name] = new FieldInitializer(builder.field, null)
            ..parent = constructor;
        }
      });
      if (member.formals != null) {
        for (KernelFormalParameterBuilder formal in member.formals) {
          if (formal.hasThis) {
            FieldInitializer initializer = fieldInitializers[formal.name];
            if (initializer != null) {
              fieldInitializers.remove(formal.name);
              initializer.value = new VariableGet(formal.declaration)
                ..parent = initializer;
              member.addInitializer(initializer);
            }
          }
        }
      }
    }
  }

  @override
  void beginInitializer(Token token) {
    debugEvent("beginInitializer");
    inInitializer = true;
  }

  @override
  void endInitializer(Token token) {
    debugEvent("endInitializer");
    assert(!inInitializer);
    final member = this.member;
    var node = pop();
    Initializer initializer;
    if (node is Initializer) {
      initializer = node;
    } else if (node is BuilderAccessor) {
      initializer = node.buildFieldInitializer(fieldInitializers);
    } else if (node is ConstructorInvocation) {
      initializer = new SuperInitializer(node.target, node.arguments);
    } else {
      if (node is! Throw) {
        node = wrapInvalid(node);
      }
      initializer =
          new LocalInitializer(new VariableDeclaration.forValue(node));
    }
    if (member is KernelConstructorBuilder) {
      member.addInitializer(initializer);
    } else {
      addCompileTimeError(
          token.charOffset, "Can't have initializers: ${member.name}");
    }
  }

  @override
  void handleNoInitializers() {
    debugEvent("NoInitializers");
  }

  @override
  void endInitializers(int count, Token beginToken, Token endToken) {
    debugEvent("Initializers");
  }

  @override
  void finishFunction(
      FormalParameters formals, AsyncMarker asyncModifier, Statement body) {
    debugEvent("finishFunction");
    KernelFunctionBuilder builder = member;
    if (builder is KernelConstructorBuilder) {
      if (asyncModifier != AsyncMarker.Sync) {
        // TODO(ahe): Change this to a null check.
        addCompileTimeError(body?.fileOffset,
            "Can't be marked as ${asyncModifier}: ${builder.name}");
      }
    } else if (builder is KernelProcedureBuilder) {
      builder.asyncModifier = asyncModifier;
    } else {
      internalError("Unhandled: ${builder.runtimeType}");
    }
    builder.body = body;
    if (formals?.optional != null) {
      Iterator<FormalParameterBuilder> formalBuilders =
          builder.formals.skip(formals.required.length).iterator;
      for (VariableDeclaration parameter in formals.optional.formals) {
        bool hasMore = formalBuilders.moveNext();
        assert(hasMore);
        VariableDeclaration realParameter = formalBuilders.current.target;
        Expression initializer = parameter.initializer ?? new NullLiteral();
        realParameter.initializer = initializer..parent = realParameter;
      }
    }
  }

  @override
  void endExpressionStatement(Token token) {
    debugEvent("ExpressionStatement");
    push(new ExpressionStatement(popForEffect()));
  }

  @override
  void endArguments(int count, Token beginToken, Token endToken) {
    debugEvent("Arguments");
    List arguments = popList(count) ?? <Expression>[];
    int firstNamedArgumentIndex = arguments.length;
    for (int i = 0; i < arguments.length; i++) {
      var node = arguments[i];
      if (node is NamedExpression) {
        firstNamedArgumentIndex =
            i < firstNamedArgumentIndex ? i : firstNamedArgumentIndex;
      } else {
        arguments[i] = toValue(node);
        if (i > firstNamedArgumentIndex) {
          arguments[i] = new NamedExpression(
              "#$i",
              buildCompileTimeError(
                  "Expected named argument.", arguments[i].fileOffset));
        }
      }
    }
    if (firstNamedArgumentIndex < arguments.length) {
      List<Expression> positional = new List<Expression>.from(
          arguments.getRange(0, firstNamedArgumentIndex));
      List<NamedExpression> named = new List<NamedExpression>.from(
          arguments.getRange(firstNamedArgumentIndex, arguments.length));
      push(new Arguments(positional, named: named));
    } else {
      push(new Arguments(arguments));
    }
  }

  @override
  void handleParenthesizedExpression(BeginGroupToken token) {
    debugEvent("ParenthesizedExpression");
    push(popForValue());
  }

  @override
  void endSend(Token beginToken, Token endToken) {
    debugEvent("Send");
    Arguments arguments = pop();
    List<DartType> typeArguments = pop();
    Object receiver = pop();
    if (arguments != null && typeArguments != null) {
      arguments.types.addAll(typeArguments);
    } else {
      assert(typeArguments == null);
    }
    if (receiver is Identifier) {
      Name name = new Name(receiver.name, library.library);
      if (arguments == null) {
        push(new IncompletePropertyAccessor(this, beginToken.charOffset, name));
      } else {
        push(new SendAccessor(this, endToken.charOffset, name, arguments));
      }
    } else if (arguments == null) {
      push(receiver);
    } else {
      push(finishSend(receiver, arguments, beginToken.charOffset));
    }
  }

  @override
  finishSend(Object receiver, Arguments arguments, int charOffset) {
    if (receiver is BuilderAccessor) {
      return receiver.doInvocation(charOffset, arguments);
    } else if (receiver is UnresolvedIdentifier) {
      return throwNoSuchMethodError(
          receiver.name.name, arguments, receiver.fileOffset);
    } else {
      return buildMethodInvocation(
          toValue(receiver), callName, arguments, charOffset);
    }
  }

  @override
  void beginCascade(Token token) {
    debugEvent("beginCascade");
    Expression expression = popForValue();
    if (expression is CascadeReceiver) {
      push(expression);
      push(new VariableAccessor(
          this, expression.fileOffset, expression.variable));
      expression.extend();
    } else {
      VariableDeclaration variable =
          new VariableDeclaration.forValue(expression);
      push(new CascadeReceiver(variable));
      push(new VariableAccessor(this, expression.fileOffset, variable));
    }
  }

  @override
  void endCascade() {
    debugEvent("endCascade");
    Expression expression = popForEffect();
    CascadeReceiver cascadeReceiver = pop();
    cascadeReceiver.finalize(expression);
    push(cascadeReceiver);
  }

  @override
  void handleBinaryExpression(Token token) {
    debugEvent("BinaryExpression");
    if (optional(".", token) || optional("..", token)) {
      return doDotOrCascadeExpression(token);
    }
    if (optional("&&", token) || optional("||", token)) {
      return doLogicalExpression(token);
    }
    if (optional("??", token)) return doIfNull(token);
    if (optional("?.", token)) return doIfNotNull(token);
    Expression argument = popForValue();
    var receiver = pop();
    bool isSuper = false;
    if (receiver is ThisAccessor && receiver.isSuper) {
      isSuper = true;
      receiver = new ThisExpression();
    }
    push(buildBinaryOperator(toValue(receiver), token, argument, isSuper));
  }

  Expression buildBinaryOperator(
      Expression a, Token token, Expression b, bool isSuper) {
    bool negate = false;
    String operator = token.stringValue;
    if (identical("!=", operator)) {
      operator = "==";
      negate = true;
    }
    if (!isBinaryOperator(operator) && !isMinusOperator(operator)) {
      return buildCompileTimeError(
          "Not an operator: '$operator'.", token.charOffset);
    } else {
      Expression result =
          makeBinary(a, new Name(operator), null, b, token.charOffset);
      if (isSuper) {
        result = toSuperMethodInvocation(result);
      }
      return negate ? new Not(result) : result;
    }
  }

  void doLogicalExpression(Token token) {
    Expression argument = popForValue();
    Expression receiver = popForValue();
    push(new LogicalExpression(receiver, token.stringValue, argument));
  }

  /// Handle `a ?? b`.
  void doIfNull(Token token) {
    Expression b = popForValue();
    Expression a = popForValue();
    VariableDeclaration variable = new VariableDeclaration.forValue(a);
    push(makeLet(
        variable,
        new ConditionalExpression(buildIsNull(new VariableGet(variable)), b,
            new VariableGet(variable), const DynamicType())));
  }

  /// Handle `a?.b(...)`.
  void doIfNotNull(Token token) {
    IncompleteSend send = pop();
    push(send.withReceiver(pop(), isNullAware: true));
  }

  void doDotOrCascadeExpression(Token token) {
    // TODO(ahe): Handle null-aware.
    IncompleteSend send = pop();
    Object receiver = optional(".", token) ? pop() : popForValue();
    push(send.withReceiver(receiver));
  }

  @override
  Expression toSuperMethodInvocation(MethodInvocation node) {
    Member target = lookupSuperMember(node.name);
    bool isNoSuchMethod = target == null;
    if (target is Procedure) {
      if (!target.isAccessor) {
        if (areArgumentsCompatible(target.function, node.arguments)) {
          // TODO(ahe): Use [DirectMethodInvocation] when possible.
          Expression result = new DirectMethodInvocation(
              new ThisExpression(), target, node.arguments);
          result = new SuperMethodInvocation(node.name, node.arguments, null);
          return result;
        } else {
          isNoSuchMethod = true;
        }
      }
    }
    if (isNoSuchMethod) {
      return throwNoSuchMethodError(
          node.name.name, node.arguments, node.fileOffset,
          isSuper: true);
    }
    // TODO(ahe): Use [DirectPropertyGet] when possible.
    Expression receiver = new DirectPropertyGet(new ThisExpression(), target);
    receiver = new SuperPropertyGet(node.name, target);
    return buildMethodInvocation(
        receiver, callName, node.arguments, node.fileOffset);
  }

  bool areArgumentsCompatible(FunctionNode function, Arguments arguments) {
    // TODO(ahe): Implement this.
    return true;
  }

  Expression throwNoSuchMethodError(
      String name, Arguments arguments, int charOffset,
      {bool isSuper: false, isGetter: false, isSetter: false}) {
    return builder_accessors.throwNoSuchMethodError(
        name, arguments, uri, charOffset, coreTypes,
        isSuper: isSuper, isGetter: isGetter, isSetter: isSetter);
  }

  @override
  Member lookupSuperMember(Name name, {bool isSetter: false}) {
    Class superclass = classBuilder.cls.superclass;
    return superclass == null
        ? null
        : hierarchy.getDispatchTarget(superclass, name, setter: isSetter);
  }

  @override
  Constructor lookupConstructor(Name name, {bool isSuper}) {
    Class cls = classBuilder.cls;
    if (isSuper) {
      cls = cls.superclass;
      while (cls.isMixinApplication) {
        cls = cls.superclass;
      }
    }
    if (cls != null) {
      for (Constructor constructor in cls.constructors) {
        if (constructor.name == name) return constructor;
      }
    }
    return null;
  }

  @override
  void beginExpression(Token token) {
    debugEvent("beginExpression");
    isFirstIdentifier = true;
  }

  Builder computeSetter(
      Builder builder, Scope scope, String name, int charOffset) {
    if (builder.isSetter) return builder;
    if (builder.isGetter) return scope.lookupSetter(name, charOffset, uri);
    return builder.isField ? (builder.isFinal ? null : builder) : null;
  }

  @override
  void handleIdentifier(Token token, IdentifierContext context) {
    debugEvent("handleIdentifier");
    String name = token.lexeme;
    if (isFirstIdentifier) {
      assert(!inInitializer ||
          this.scope == enclosingScope ||
          this.scope.parent == enclosingScope);
      // This deals with this kind of initializer: `C(a) : a = a;`
      Scope scope = inInitializer ? enclosingScope : this.scope;
      Builder builder = scope.lookup(name, token.charOffset, uri);
      push(builderToFirstExpression(builder, name, token.charOffset));
    } else {
      push(new Identifier(name)..fileOffset = token.charOffset);
    }
  }

  @override
  builderToFirstExpression(Builder builder, String name, int charOffset,
      {bool isPrefix: false}) {
    if (builder == null || (!isInstanceContext && builder.isInstanceMember)) {
      if (!isPrefix && identical(name, "dynamic") && builder == null) {
        return new KernelNamedTypeBuilder(name, null, charOffset, uri);
      }
      Name n = new Name(name, library.library);
      if (!isPrefix && isInstanceContext) {
        assert(builder == null);
        return new ThisPropertyAccessor(this, charOffset, n, null, null);
      } else {
        return new UnresolvedIdentifier(n)..fileOffset = charOffset;
      }
    } else if (builder.isTypeDeclaration) {
      return builder;
    } else if (builder.isLocal) {
      return new VariableAccessor(this, charOffset, builder.target);
    } else if (builder.isInstanceMember) {
      return new ThisPropertyAccessor(
          this, charOffset, new Name(name, library.library), null, null);
    } else if (builder.isRegularMethod) {
      assert(builder.isStatic || builder.isTopLevel);
      return new StaticAccessor(this, charOffset, builder.target, null);
    } else if (builder is PrefixBuilder) {
      return builder;
    } else if (builder is MixedAccessor) {
      return new StaticAccessor(
          this, charOffset, builder.getter.target, builder.setter.target);
    } else {
      if (builder is AccessErrorBuilder) {
        AccessErrorBuilder error = builder;
        builder = error.builder;
      }
      if (builder.target == null) {
        return internalError("Unhandled: ${builder}");
      }
      Member getter = builder.target.hasGetter ? builder.target : null;
      Member setter = builder.target.hasSetter ? builder.target : null;
      setter ??= computeSetter(builder, scope, name, charOffset)?.target;
      return new StaticAccessor(this, charOffset, getter, setter);
    }
  }

  @override
  void handleQualified(Token period) {
    debugEvent("Qualified");
    Identifier name = pop();
    var receiver = pop();
    push([receiver, name]);
  }

  @override
  void beginLiteralString(Token token) {
    debugEvent("beginLiteralString");
    push(token);
  }

  @override
  void handleStringPart(Token token) {
    debugEvent("StringPart");
    push(token);
  }

  @override
  void endLiteralString(int interpolationCount, Token endToken) {
    debugEvent("endLiteralString");
    if (interpolationCount == 0) {
      Token token = pop();
      push(new StringLiteral(unescapeString(token.lexeme)));
    } else {
      List parts = popList(1 + interpolationCount * 2);
      Token first = parts.first;
      Token last = parts.last;
      Quote quote = analyzeQuote(first.lexeme);
      List<Expression> expressions = <Expression>[];
      expressions
          .add(new StringLiteral(unescapeFirstStringPart(first.lexeme, quote)));
      for (int i = 1; i < parts.length - 1; i++) {
        var part = parts[i];
        if (part is Token) {
          expressions.add(new StringLiteral(unescape(part.lexeme, quote)));
        } else {
          expressions.add(toValue(part));
        }
      }
      expressions
          .add(new StringLiteral(unescapeLastStringPart(last.lexeme, quote)));
      push(new StringConcatenation(expressions)
        ..fileOffset = endToken.charOffset);
    }
  }

  @override
  void handleScript(Token token) {
    debugEvent("Script");
  }

  @override
  void handleStringJuxtaposition(int literalCount) {
    debugEvent("StringJuxtaposition");
    List<Expression> parts = popListForValue(literalCount);
    List<Expression> expressions;
    // Flatten string juxtapositions of string interpolation.
    for (int i = 0; i < parts.length; i++) {
      Expression part = parts[i];
      if (part is StringConcatenation) {
        if (expressions == null) {
          expressions = parts.sublist(0, i);
        }
        expressions.addAll(part.expressions);
      } else {
        if (expressions != null) {
          expressions.add(part);
        }
      }
    }
    push(new StringConcatenation(expressions ?? parts));
  }

  @override
  void handleLiteralInt(Token token) {
    debugEvent("LiteralInt");
    push(new IntLiteral(int.parse(token.lexeme)));
  }

  @override
  void handleEmptyFunctionBody(Token semicolon) {
    debugEvent("ExpressionFunctionBody");
    endBlockFunctionBody(0, null, semicolon);
  }

  @override
  void handleExpressionFunctionBody(Token arrowToken, Token endToken) {
    debugEvent("ExpressionFunctionBody");
    endReturnStatement(true, arrowToken, endToken);
  }

  @override
  void endReturnStatement(
      bool hasExpression, Token beginToken, Token endToken) {
    debugEvent("ReturnStatement");
    Expression expression = hasExpression ? popForValue() : null;
    if (expression != null && inConstructor) {
      push(buildCompileTimeErrorStatement(
          "Can't return from a constructor.", beginToken.charOffset));
    } else {
      push(new ReturnStatement(expression)..fileOffset = beginToken.charOffset);
    }
  }

  @override
  void endIfStatement(Token ifToken, Token elseToken) {
    Statement elsePart = popStatementIfNotNull(elseToken);
    Statement thenPart = popStatement();
    Expression condition = popForValue();
    push(new IfStatement(condition, thenPart, elsePart));
  }

  @override
  void endVariableInitializer(Token assignmentOperator) {
    debugEvent("VariableInitializer");
    assert(assignmentOperator.stringValue == "=");
    Expression initializer = popForValue();
    Identifier identifier = pop();
    push(new VariableDeclaration(identifier.name, initializer: initializer)
      ..fileEqualsOffset = assignmentOperator.charOffset);
  }

  @override
  void handleNoVariableInitializer(Token token) {
    debugEvent("NoVariableInitializer");
  }

  @override
  void endFieldInitializer(Token assignmentOperator) {
    debugEvent("FieldInitializer");
    assert(assignmentOperator.stringValue == "=");
    push(popForValue());
  }

  @override
  void handleNoFieldInitializer(Token token) {
    debugEvent("NoFieldInitializer");
    push(NullValue.FieldInitializer);
  }

  @override
  void endInitializedIdentifier(Token nameToken) {
    // TODO(ahe): Use [InitializedIdentifier] here?
    debugEvent("InitializedIdentifier");
    TreeNode node = pop();
    VariableDeclaration variable;
    if (node is VariableDeclaration) {
      variable = node;
    } else if (node is Identifier) {
      variable = new VariableDeclaration(node.name);
    } else {
      internalError("unhandled identifier: ${node.runtimeType}");
    }
    variable.fileOffset = nameToken.charOffset;
    push(variable);
    scope[variable.name] = new KernelVariableBuilder(
        variable, member ?? classBuilder ?? library, uri);
  }

  @override
  void endVariablesDeclaration(int count, Token endToken) {
    debugEvent("VariablesDeclaration");
    List<VariableDeclaration> variables = popList(count);
    DartType type = pop();
    int modifiers = Modifier.validate(pop());
    bool isConst = (modifiers & constMask) != 0;
    bool isFinal = (modifiers & finalMask) != 0;
    if (type != null || isConst || isFinal) {
      type ??= const DynamicType();
      for (VariableDeclaration variable in variables) {
        variable
          ..type = type
          ..isConst = isConst
          ..isFinal = isFinal;
      }
    }
    if (variables.length != 1) {
      push(variables);
    } else {
      push(variables.single);
    }
  }

  @override
  void endBlock(int count, Token beginToken, Token endToken) {
    debugEvent("Block");
    Block block = popBlock(count);
    exitLocalScope();
    push(block);
  }

  @override
  void handleAssignmentExpression(Token token) {
    debugEvent("AssignmentExpression");
    Expression value = popForValue();
    var accessor = pop();
    if (accessor is TypeDeclarationBuilder) {
      push(wrapInvalid(new TypeLiteral(
          accessor.buildTypesWithBuiltArguments(library, null))));
    } else if (accessor is! BuilderAccessor) {
      push(buildCompileTimeError("Can't assign to this.", token.charOffset));
    } else {
      push(new DelayedAssignment(
          this, token.charOffset, accessor, value, token.stringValue));
    }
  }

  @override
  void enterLoop(int charOffset) {
    if (peek() is LabelTarget) {
      LabelTarget target = peek();
      enterBreakTarget(charOffset, target.breakTarget);
      enterContinueTarget(charOffset, target.continueTarget);
    } else {
      enterBreakTarget(charOffset);
      enterContinueTarget(charOffset);
    }
  }

  void exitLoopOrSwitch(Statement statement) {
    if (compileTimeErrorInLoopOrSwitch != null) {
      push(compileTimeErrorInLoopOrSwitch);
      compileTimeErrorInLoopOrSwitch = null;
    } else {
      push(statement);
    }
  }

  @override
  void endForStatement(
      int updateExpressionCount, Token beginToken, Token endToken) {
    debugEvent("ForStatement");
    Statement body = popStatement();
    List<Expression> updates = popListForEffect(updateExpressionCount);
    Statement conditionStatement = popStatement();
    Expression condition = null;
    if (conditionStatement is ExpressionStatement) {
      condition = conditionStatement.expression;
    } else {
      assert(conditionStatement is EmptyStatement);
    }
    List<VariableDeclaration> variables = <VariableDeclaration>[];
    dynamic variableOrExpression = pop();
    Statement begin;
    if (variableOrExpression is BuilderAccessor) {
      variableOrExpression = variableOrExpression.buildForEffect();
    }
    if (variableOrExpression is VariableDeclaration) {
      variables.add(variableOrExpression);
    } else if (variableOrExpression is List) {
      // TODO(sigmund): remove this assignment (see issue #28651)
      Iterable vars = variableOrExpression;
      variables.addAll(vars);
    } else if (variableOrExpression == null) {
      // Do nothing.
    } else if (variableOrExpression is Expression) {
      begin = new ExpressionStatement(variableOrExpression);
    } else {
      return internalError("Unhandled: ${variableOrExpression.runtimeType}");
    }
    exitLocalScope();
    JumpTarget continueTarget = exitContinueTarget();
    JumpTarget breakTarget = exitBreakTarget();
    if (continueTarget.hasUsers) {
      body = new LabeledStatement(body);
      continueTarget.resolveContinues(body);
    }
    Statement result = new ForStatement(variables, condition, updates, body);
    if (begin != null) {
      result = new Block(<Statement>[begin, result]);
    }
    if (breakTarget.hasUsers) {
      result = new LabeledStatement(result);
      breakTarget.resolveBreaks(result);
    }
    exitLoopOrSwitch(result);
  }

  @override
  void endAwaitExpression(Token beginToken, Token endToken) {
    debugEvent("AwaitExpression");
    push(new AwaitExpression(popForValue()));
  }

  @override
  void handleAsyncModifier(Token asyncToken, Token starToken) {
    debugEvent("AsyncModifier");
    push(asyncMarkerFromTokens(asyncToken, starToken));
  }

  @override
  void handleLiteralList(
      int count, Token beginToken, Token constKeyword, Token endToken) {
    debugEvent("LiteralList");
    List<Expression> expressions = popListForValue(count);
    List<DartType> typeArguments = pop();
    DartType typeArgument = const DynamicType();
    if (typeArguments != null) {
      typeArgument = typeArguments.first;
      if (typeArguments.length > 1) {
        typeArgument = const DynamicType();
        warning(
            "Too many type arguments on List literal.", beginToken.charOffset);
      }
    }
    push(new ListLiteral(expressions,
        typeArgument: typeArgument, isConst: constKeyword != null)
      ..fileOffset = constKeyword?.charOffset ?? beginToken.charOffset);
  }

  @override
  void handleLiteralBool(Token token) {
    debugEvent("LiteralBool");
    bool value = optional("true", token);
    assert(value || optional("false", token));
    push(new BoolLiteral(value));
  }

  @override
  void handleLiteralDouble(Token token) {
    debugEvent("LiteralDouble");
    push(new DoubleLiteral(double.parse(token.lexeme)));
  }

  @override
  void handleLiteralNull(Token token) {
    debugEvent("LiteralNull");
    push(new NullLiteral());
  }

  @override
  void handleLiteralMap(
      int count, Token beginToken, Token constKeyword, Token endToken) {
    debugEvent("LiteralMap");
    List<MapEntry> entries = popList(count) ?? <MapEntry>[];
    List<DartType> typeArguments = pop();
    DartType keyType = const DynamicType();
    DartType valueType = const DynamicType();
    if (typeArguments != null) {
      if (typeArguments.length != 2) {
        keyType = const DynamicType();
        valueType = const DynamicType();
        warning(
            "Map literal requires two type arguments.", beginToken.charOffset);
      } else {
        keyType = typeArguments[0];
        valueType = typeArguments[1];
      }
    }
    push(new MapLiteral(entries,
        keyType: keyType, valueType: valueType, isConst: constKeyword != null)
      ..fileOffset = constKeyword?.charOffset ?? beginToken.charOffset);
  }

  @override
  void endLiteralMapEntry(Token colon, Token endToken) {
    debugEvent("LiteralMapEntry");
    Expression value = popForValue();
    Expression key = popForValue();
    push(new MapEntry(key, value));
  }

  @override
  void beginLiteralSymbol(Token token) {
    isFirstIdentifier = false;
  }

  String symbolPartToString(name) {
    if (name is Identifier) {
      return name.name;
    } else if (name is Operator) {
      return name.name;
    } else {
      return internalError("Unhandled: ${name.runtimeType}");
    }
  }

  @override
  void endLiteralSymbol(Token hashToken, int identifierCount) {
    debugEvent("LiteralSymbol");
    String value;
    if (identifierCount == 1) {
      value = symbolPartToString(popForValue());
    } else {
      List parts = popList(identifierCount);
      value = symbolPartToString(parts.first);
      for (int i = 1; i < parts.length; i++) {
        value += ".${symbolPartToString(parts[i])}";
      }
    }
    push(new SymbolLiteral(value));
  }

  DartType toKernelType(String name, List<DartType> arguments, int charOffset) {
    if (identical(name, "void")) return const VoidType();
    if (identical(name, "dynamic")) return const DynamicType();
    Builder builder = scope.lookup(name, charOffset, uri);
    if (builder is TypeDeclarationBuilder) {
      return builder.buildTypesWithBuiltArguments(library, arguments);
    }
    if (builder == null) {
      warning("Type not found: '$name'.", charOffset);
    } else {
      warning("Not a type: '$name'.", charOffset);
    }
    // TODO(ahe): Create an error somehow.
    return const DynamicType();
  }

  @override
  void handleType(Token beginToken, Token endToken) {
    // TODO(ahe): The scope is wrong for return types of generic functions.
    debugEvent("Type");
    List<DartType> arguments = pop();
    dynamic name = pop();
    if (name is List) {
      if (name.length != 2) {
        internalError("Unexpected: $name.length");
      }
      var prefix = name[0];
      if (prefix is Identifier) {
        prefix = prefix.name;
      }
      var suffix = name[1];
      if (suffix is Identifier) {
        suffix = suffix.name;
      }
      Builder builder;
      if (prefix is Builder) {
        builder = prefix;
      } else {
        builder = scope.lookup(prefix, beginToken.charOffset, uri);
      }
      if (builder is PrefixBuilder) {
        name = builder.exports[suffix];
      } else {
        push(const DynamicType());
        addCompileTimeError(beginToken.charOffset,
            "Can't be used as a type: '${debugName(prefix, suffix)}'.");
        return;
      }
    }
    if (name is Identifier) {
      name = name.name;
    }
    if (name is BuilderAccessor) {
      warning("'${beginToken.lexeme}' isn't a type.", beginToken.charOffset);
      push(const DynamicType());
    } else if (name is UnresolvedIdentifier) {
      warning("'${name.name}' isn't a type.", beginToken.charOffset);
      push(const DynamicType());
    } else if (name is TypeVariableBuilder) {
      push(name.buildTypesWithBuiltArguments(library, arguments));
    } else if (name is TypeDeclarationBuilder) {
      push(name.buildTypesWithBuiltArguments(library, arguments));
    } else if (name is TypeBuilder) {
      push(name.build(library));
    } else {
      push(toKernelType(name, arguments, beginToken.charOffset));
    }
    if (peek() is TypeParameterType) {
      TypeParameterType type = peek();
      if (!isInstanceContext && type.parameter.parent is Class) {
        pop();
        warning("Type variables can only be used in instance methods.",
            beginToken.charOffset);
        push(const DynamicType());
      }
    }
  }

  @override
  void handleVoidKeyword(Token token) {
    debugEvent("VoidKeyword");
    push(const VoidType());
  }

  @override
  void handleAsOperator(Token operator, Token endToken) {
    debugEvent("AsOperator");
    DartType type = pop();
    Expression expression = popForValue();
    push(new AsExpression(expression, type)..fileOffset = operator.charOffset);
  }

  @override
  void handleIsOperator(Token operator, Token not, Token endToken) {
    debugEvent("IsOperator");
    DartType type = pop();
    Expression expression = popForValue();
    expression = new IsExpression(expression, type)
      ..fileOffset = operator.charOffset;
    if (not != null) {
      expression = new Not(expression);
    }
    push(expression);
  }

  @override
  void handleConditionalExpression(Token question, Token colon) {
    debugEvent("ConditionalExpression");
    Expression elseExpression = popForValue();
    Expression thenExpression = popForValue();
    Expression condition = popForValue();
    push(new ConditionalExpression(
        condition, thenExpression, elseExpression, const DynamicType()));
  }

  @override
  void endThrowExpression(Token throwToken, Token endToken) {
    debugEvent("ThrowExpression");
    Expression expression = popForValue();
    push(new Throw(expression)..fileOffset = throwToken.charOffset);
  }

  @override
  void endFormalParameter(
      Token covariantKeyword, Token thisKeyword, FormalParameterType kind) {
    debugEvent("FormalParameter");
    // TODO(ahe): Need beginToken here.
    int charOffset = thisKeyword?.charOffset;
    if (thisKeyword != null) {
      if (!inConstructor) {
        addCompileTimeError(thisKeyword.charOffset,
            "'this' parameters can only be used on constructors.");
        thisKeyword = null;
      }
    }
    Identifier name = pop();
    DartType type = pop();
    pop(); // Modifiers.
    ignore(Unhandled.Metadata);
    VariableDeclaration variable;
    if (!inCatchClause && functionNestingLevel == 0) {
      dynamic builder = formalParameterScope.lookup(name.name, charOffset, uri);
      if (builder == null) {
        if (thisKeyword == null) {
          internalError("Internal error: formal missing for '${name.name}'");
        } else {
          addCompileTimeError(thisKeyword.charOffset,
              "'${name.name}' isn't a field in this class.");
          thisKeyword = null;
        }
      } else if (thisKeyword == null) {
        variable = builder.build(library);
        variable.initializer = name.initializer;
      } else if (builder.isField && builder.parent == classBuilder) {
        FieldBuilder field = builder;
        if (type != null) {
          nit("Ignoring type on 'this' parameter '${name.name}'.",
              thisKeyword.charOffset);
        }
        type = field.target.type ?? const DynamicType();
        variable = new VariableDeclaration(name.name,
            type: type, initializer: name.initializer);
      } else {
        addCompileTimeError(
            name.fileOffset, "'${name.name}' isn't a field in this class.");
      }
    }
    variable ??= new VariableDeclaration(name.name,
        type: type ?? const DynamicType(),
        initializer: name.initializer)..fileOffset = name.fileOffset;
    push(variable);
  }

  @override
  void endOptionalFormalParameters(
      int count, Token beginToken, Token endToken) {
    debugEvent("OptionalFormalParameters");
    FormalParameterType kind = optional("{", beginToken)
        ? FormalParameterType.NAMED
        : FormalParameterType.POSITIONAL;
    push(new OptionalFormals(kind, popList(count) ?? []));
  }

  @override
  void beginFunctionTypedFormalParameter(Token token) {
    debugEvent("beginFunctionTypedFormalParameter");
    functionNestingLevel++;
  }

  @override
  void endFunctionTypedFormalParameter(
      Token covariantKeyword, Token thisKeyword, FormalParameterType kind) {
    debugEvent("FunctionTypedFormalParameter");
    if (inCatchClause || functionNestingLevel != 0) {
      exitLocalScope();
    }
    FormalParameters formals = pop();
    ignore(Unhandled.TypeVariables);
    Identifier name = pop();
    DartType returnType = pop();
    push(formals.toFunctionType(returnType));
    push(name);
    functionNestingLevel--;
  }

  @override
  void handleValuedFormalParameter(Token equals, Token token) {
    debugEvent("ValuedFormalParameter");
    Expression initializer = popForValue();
    Identifier name = pop();
    push(new InitializedIdentifier(name.name, initializer));
  }

  @override
  void handleFormalParameterWithoutValue(Token token) {
    debugEvent("FormalParameterWithoutValue");
  }

  @override
  void endFormalParameters(int count, Token beginToken, Token endToken) {
    debugEvent("FormalParameters");
    OptionalFormals optional;
    if (count > 0 && peek() is OptionalFormals) {
      optional = pop();
      count--;
    }
    FormalParameters formals = new FormalParameters(
        popList(count) ?? <VariableDeclaration>[], optional);
    push(formals);
    if (inCatchClause || functionNestingLevel != 0) {
      enterLocalScope(formals.computeFormalParameterScope(
          scope, member ?? classBuilder ?? library));
    }
  }

  @override
  void beginCatchClause(Token token) {
    debugEvent("beginCatchClause");
    inCatchClause = true;
  }

  @override
  void endCatchClause(Token token) {
    debugEvent("CatchClause");
    inCatchClause = false;
  }

  @override
  void handleCatchBlock(Token onKeyword, Token catchKeyword) {
    debugEvent("CatchBlock");
    Block body = pop();
    if (catchKeyword != null) {
      exitLocalScope();
    }
    FormalParameters catchParameters = popIfNotNull(catchKeyword);
    DartType type = popIfNotNull(onKeyword) ?? const DynamicType();
    VariableDeclaration exception;
    VariableDeclaration stackTrace;
    if (catchParameters != null) {
      if (catchParameters.required.length > 0) {
        exception = catchParameters.required[0];
      }
      if (catchParameters.required.length > 1) {
        stackTrace = catchParameters.required[1];
      }
      if (catchParameters.required.length > 2 ||
          catchParameters.optional != null) {
        body = new Block(<Statement>[new InvalidStatement()]);
        compileTimeErrorInTry ??= buildCompileTimeErrorStatement(
            "Invalid catch arguments.", catchKeyword.next.charOffset);
      }
    }
    push(new Catch(exception, body, guard: type, stackTrace: stackTrace));
  }

  @override
  void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
    Statement finallyBlock = popStatementIfNotNull(finallyKeyword);
    List<Catch> catches = popList(catchCount);
    Statement tryBlock = popStatement();
    if (compileTimeErrorInTry == null) {
      if (catches != null) {
        tryBlock = new TryCatch(tryBlock, catches);
      }
      if (finallyBlock != null) {
        tryBlock = new TryFinally(tryBlock, finallyBlock);
      }
      push(tryBlock);
    } else {
      push(compileTimeErrorInTry);
      compileTimeErrorInTry = null;
    }
  }

  @override
  void handleNoExpression(Token token) {
    debugEvent("NoExpression");
    push(NullValue.Expression);
  }

  @override
  void handleIndexedExpression(
      Token openCurlyBracket, Token closeCurlyBracket) {
    debugEvent("IndexedExpression");
    Expression index = popForValue();
    var receiver = pop();
    if (receiver is ThisAccessor && receiver.isSuper) {
      push(new SuperIndexAccessor(this, receiver.charOffset, index,
          lookupSuperMember(indexGetName), lookupSuperMember(indexSetName)));
    } else {
      push(IndexAccessor.make(this, openCurlyBracket.charOffset,
          toValue(receiver), index, null, null));
    }
  }

  @override
  void handleUnaryPrefixExpression(Token token) {
    debugEvent("UnaryPrefixExpression");
    var receiver = pop();
    if (optional("!", token)) {
      push(new Not(toValue(receiver)));
    } else {
      String operator = token.stringValue;
      if (optional("-", token)) {
        operator = "unary-";
      }
      if (receiver is ThisAccessor && receiver.isSuper) {
        push(toSuperMethodInvocation(buildMethodInvocation(
            new ThisExpression()..fileOffset = receiver.charOffset,
            new Name(operator),
            new Arguments.empty(),
            token.charOffset)));
      } else {
        push(buildMethodInvocation(toValue(receiver), new Name(operator),
            new Arguments.empty(), token.charOffset));
      }
    }
  }

  Name incrementOperator(Token token) {
    if (optional("++", token)) return plusName;
    if (optional("--", token)) return minusName;
    return internalError("Unknown increment operator: ${token.lexeme}");
  }

  @override
  void handleUnaryPrefixAssignmentExpression(Token token) {
    debugEvent("UnaryPrefixAssignmentExpression");
    var accessor = pop();
    if (accessor is BuilderAccessor) {
      push(accessor.buildPrefixIncrement(
          incrementOperator(token), token.charOffset));
    } else {
      push(wrapInvalid(toValue(accessor)));
    }
  }

  @override
  void handleUnaryPostfixAssignmentExpression(Token token) {
    debugEvent("UnaryPostfixAssignmentExpression");
    var accessor = pop();
    if (accessor is BuilderAccessor) {
      push(new DelayedPostfixIncrement(
          this, token.charOffset, accessor, incrementOperator(token), null));
    } else {
      push(wrapInvalid(toValue(accessor)));
    }
  }

  @override
  void endConstructorReference(
      Token start, Token periodBeforeName, Token endToken) {
    debugEvent("ConstructorReference");
    // A constructor reference can contain up to three identifiers:
    //
    //     a) type <type-arguments>?
    //     b) type <type-arguments>? . name
    //     c) prefix . type <type-arguments>?
    //     d) prefix . type <type-arguments>? . name
    //
    // This isn't a legal constructor reference:
    //
    //     type . name <type-arguments>
    //
    // But the parser can't tell this from type c) above.
    //
    // This method pops 2 (or 3 if periodBeforeName != null) values from the
    // stack and pushes 3 values: a type, a list of type arguments, and a name.
    //
    // If the constructor reference can be resolved, type is either a
    // ClassBuilder, or a ThisPropertyAccessor. Otherwise, it's an error that
    // should be handled later.
    Identifier suffix = popIfNotNull(periodBeforeName);
    Identifier identifier;
    List<DartType> typeArguments = pop();
    dynamic type = pop();
    if (type is List) {
      var prefix = type[0];
      identifier = type[1];
      if (prefix is PrefixBuilder) {
        // TODO(ahe): Handle privacy in prefix.exports.
        type = builderToFirstExpression(
            prefix.exports[identifier.name], identifier.name, start.charOffset);
        identifier = null;
      } else if (prefix is ClassBuilder) {
        type = prefix;
      } else {
        type = new Identifier(start.lexeme)..fileOffset = start.charOffset;
      }
    }
    String name;
    if (identifier != null && suffix != null) {
      name = "${identifier.name}.${suffix.name}";
    } else if (identifier != null) {
      name = identifier.name;
    } else if (suffix != null) {
      name = suffix.name;
    } else {
      name = "";
    }
    push(type);
    push(typeArguments ?? NullValue.TypeArguments);
    push(name);
  }

  @override
  Expression buildStaticInvocation(Member target, Arguments arguments,
      {bool isConst: false, int charOffset: -1}) {
    List<TypeParameter> typeParameters = target.function.typeParameters;
    if (target is Constructor) {
      typeParameters = target.enclosingClass.typeParameters;
    }
    if (!addDefaultArguments(target.function, arguments, typeParameters)) {
      return throwNoSuchMethodError(target.name.name, arguments, charOffset);
    }
    if (target is Constructor) {
      return new ConstructorInvocation(target, arguments)..isConst = isConst;
    } else {
      return new StaticInvocation(target, arguments)..isConst = isConst;
    }
  }

  bool addDefaultArguments(FunctionNode function, Arguments arguments,
      List<TypeParameter> typeParameters) {
    bool missingInitializers = false;

    Expression defaultArgumentFrom(Expression expression) {
      if (expression == null) {
        missingInitializers = true;
        return null;
      }
      cloner ??= new CloneVisitor();
      return cloner.clone(expression);
    }

    if (arguments.positional.length < function.requiredParameterCount ||
        arguments.positional.length > function.positionalParameters.length) {
      return false;
    }
    for (int i = arguments.positional.length;
        i < function.positionalParameters.length;
        i++) {
      var expression =
          defaultArgumentFrom(function.positionalParameters[i].initializer);
      expression?.parent = arguments;
      arguments.positional.add(expression);
    }
    Map<String, VariableDeclaration> names;
    if (function.namedParameters.isNotEmpty) {
      names = <String, VariableDeclaration>{};
      for (VariableDeclaration parameter in function.namedParameters) {
        names[parameter.name] = parameter;
      }
    }
    if (arguments.named.isNotEmpty) {
      if (names == null) return false;
      for (NamedExpression argument in arguments.named) {
        VariableDeclaration parameter = names.remove(argument.name);
        if (parameter == null) {
          return false;
        }
      }
    }
    if (names != null) {
      for (String name in names.keys) {
        VariableDeclaration parameter = names[name];
        arguments.named.add(new NamedExpression(
            name, defaultArgumentFrom(parameter.initializer))
          ..parent = arguments);
      }
    }
    if (typeParameters.length != arguments.types.length) {
      arguments.types.clear();
      for (int i = 0; i < typeParameters.length; i++) {
        arguments.types.add(const DynamicType());
      }
    }

    if (missingInitializers) {
      library.addArgumentsWithMissingDefaultValues(arguments, function);
    }
    return true;
  }

  @override
  void handleNewExpression(Token token) {
    debugEvent("NewExpression");
    Arguments arguments = pop();
    String name = pop();
    List<DartType> typeArguments = pop();
    var type = pop();

    if (arguments == null) {
      push(buildCompileTimeError("No arguments.", token.charOffset));
      return;
    }

    if (typeArguments != null) {
      assert(arguments.types.isEmpty);
      arguments.types.addAll(typeArguments);
    }

    String errorName;
    if (type is ClassBuilder) {
      Builder b = type.findConstructorOrFactory(name);
      Member target;
      if (b == null) {
        // Not found. Reported below.
      } else if (b.isConstructor) {
        if (type.isAbstract) {
          // TODO(ahe): Generate abstract instantiation error.
        } else {
          target = b.target;
        }
      } else if (b.isFactory) {
        target = getRedirectionTarget(b.target);
        if (target == null) {
          push(buildCompileTimeError(
              "Cyclic definition of factory '${name}'.", token.charOffset));
          return;
        }
      }
      if (target is Constructor ||
          (target is Procedure && target.kind == ProcedureKind.Factory)) {
        push(buildStaticInvocation(target, arguments,
            isConst: optional("const", token), charOffset: token.charOffset));
        return;
      } else {
        errorName = debugName(type.name, name);
      }
    } else {
      errorName = debugName(getNodeName(type), name);
    }
    errorName ??= name;
    push(throwNoSuchMethodError(errorName, arguments, token.charOffset));
  }

  @override
  void handleConstExpression(Token token) {
    debugEvent("ConstExpression");
    handleNewExpression(token);
  }

  @override
  void endTypeArguments(int count, Token beginToken, Token endToken) {
    debugEvent("TypeArguments");
    push(popList(count));
  }

  @override
  void handleThisExpression(Token token) {
    debugEvent("ThisExpression");
    if (isFirstIdentifier && isInstanceContext) {
      push(new ThisAccessor(this, token.charOffset, inInitializer));
    } else {
      push(new IncompleteError(
          this, token.charOffset, "Expected identifier, but got 'this'."));
    }
  }

  @override
  void handleSuperExpression(Token token) {
    debugEvent("SuperExpression");
    if (isFirstIdentifier && isInstanceContext) {
      Member member = this.member.target;
      member.transformerFlags |= TransformerFlag.superCalls;
      push(new ThisAccessor(this, token.charOffset, inInitializer,
          isSuper: true));
    } else {
      push(new IncompleteError(
          this, token.charOffset, "Expected identifier, but got 'super'."));
    }
  }

  @override
  void handleNamedArgument(Token colon) {
    debugEvent("NamedArgument");
    Expression value = popForValue();
    Identifier identifier = pop();
    push(new NamedExpression(identifier.name, value));
  }

  @override
  void endFunctionName(Token token) {
    debugEvent("FunctionName");
    Identifier name = pop();
    VariableDeclaration variable =
        new VariableDeclaration(name.name, isFinal: true);
    push(new FunctionDeclaration(
        variable, new FunctionNode(new InvalidStatement())));
    scope[variable.name] = new KernelVariableBuilder(
        variable, member ?? classBuilder ?? library, uri);
    enterLocalScope();
  }

  void enterFunction() {
    debugEvent("enterFunction");
    functionNestingLevel++;
    push(switchScope ?? NullValue.SwitchScope);
    switchScope = null;
  }

  void exitFunction() {
    debugEvent("exitFunction");
    functionNestingLevel--;
    switchScope = pop();
  }

  @override
  void beginFunction(Token token) {
    debugEvent("beginFunction");
    enterFunction();
  }

  @override
  void beginUnnamedFunction(Token token) {
    debugEvent("beginUnnamedFunction");
    enterFunction();
  }

  @override
  void endFunction(Token getOrSet, Token endToken) {
    debugEvent("Function");
    Statement body = popStatement();
    AsyncMarker asyncModifier = pop();
    if (functionNestingLevel != 0) {
      exitLocalScope();
    }
    FormalParameters formals = pop();
    List<TypeParameter> typeParameters = pop();
    push(formals.addToFunction(new FunctionNode(body,
        typeParameters: typeParameters, asyncMarker: asyncModifier)));
  }

  @override
  void endFunctionDeclaration(Token token) {
    debugEvent("FunctionDeclaration");
    FunctionNode function = pop();
    exitLocalScope();
    FunctionDeclaration declaration = pop();
    function.returnType = pop() ?? const DynamicType();
    pop(); // Modifiers.
    exitFunction();
    declaration.function = function;
    function.parent = declaration;
    push(declaration);
  }

  @override
  void endUnnamedFunction(Token token) {
    debugEvent("UnnamedFunction");
    Statement body = popStatement();
    AsyncMarker asyncModifier = pop();
    exitLocalScope();
    FormalParameters formals = pop();
    exitFunction();
    List<TypeParameter> typeParameters = pop();
    FunctionNode function = formals.addToFunction(new FunctionNode(body,
        typeParameters: typeParameters, asyncMarker: asyncModifier));
    push(new FunctionExpression(function));
  }

  @override
  void endDoWhileStatement(
      Token doKeyword, Token whileKeyword, Token endToken) {
    debugEvent("DoWhileStatement");
    Expression condition = popForValue();
    Statement body = popStatement();
    JumpTarget continueTarget = exitContinueTarget();
    JumpTarget breakTarget = exitBreakTarget();
    if (continueTarget.hasUsers) {
      body = new LabeledStatement(body);
      continueTarget.resolveContinues(body);
    }
    Statement result = new DoStatement(body, condition);
    if (breakTarget.hasUsers) {
      result = new LabeledStatement(result);
      breakTarget.resolveBreaks(result);
    }
    exitLoopOrSwitch(result);
  }

  @override
  void beginForInExpression(Token token) {
    enterLocalScope(scope.parent);
  }

  @override
  void endForInExpression(Token token) {
    debugEvent("ForInExpression");
    Expression expression = popForValue();
    exitLocalScope();
    push(expression ?? NullValue.Expression);
  }

  @override
  void endForIn(Token awaitToken, Token forToken, Token leftParenthesis,
      Token inKeyword, Token rightParenthesis, Token endToken) {
    debugEvent("ForIn");
    Statement body = popStatement();
    Expression expression = popForValue();
    var lvalue = pop();
    exitLocalScope();
    JumpTarget continueTarget = exitContinueTarget();
    JumpTarget breakTarget = exitBreakTarget();
    if (continueTarget.hasUsers) {
      body = new LabeledStatement(body);
      continueTarget.resolveContinues(body);
    }
    VariableDeclaration variable;
    if (lvalue is VariableDeclaration) {
      variable = lvalue;
    } else if (lvalue is BuilderAccessor) {
      /// We are in this case, where `lvalue` isn't a [VariableDeclaration]:
      ///
      ///     for (lvalue in expression) body
      ///
      /// This is normalized to:
      ///
      ///     for (final #t in expression) {
      ///       lvalue = #t;
      ///       body;
      ///     }
      variable = new VariableDeclaration.forValue(null);
      body = combineStatements(
          new ExpressionStatement(lvalue
              .buildAssignment(new VariableGet(variable), voidContext: true)),
          body);
    } else {
      variable = new VariableDeclaration.forValue(buildCompileTimeError(
          "Expected lvalue, but got ${lvalue}", forToken.next.next.charOffset));
    }
    Statement result = new ForInStatement(variable, expression, body,
        isAsync: awaitToken != null)..fileOffset = body.fileOffset;
    if (breakTarget.hasUsers) {
      result = new LabeledStatement(result);
      breakTarget.resolveBreaks(result);
    }
    exitLoopOrSwitch(result);
  }

  @override
  void handleLabel(Token token) {
    debugEvent("Label");
    Identifier identifier = pop();
    push(new Label(identifier.name));
  }

  @override
  void beginLabeledStatement(Token token, int labelCount) {
    debugEvent("beginLabeledStatement");
    List<Label> labels = popList(labelCount);
    enterLocalScope();
    LabelTarget target =
        new LabelTarget(member, functionNestingLevel, token.charOffset);
    for (Label label in labels) {
      scope.declareLabel(label.name, target);
    }
    push(target);
  }

  @override
  void endLabeledStatement(int labelCount) {
    debugEvent("LabeledStatement");
    Statement statement = popStatement();
    LabelTarget target = pop();
    exitLocalScope();
    if (target.breakTarget.hasUsers) {
      if (statement is! LabeledStatement) {
        statement = new LabeledStatement(statement);
      }
      target.breakTarget.resolveBreaks(statement);
    }
    if (target.continueTarget.hasUsers) {
      if (statement is! LabeledStatement) {
        statement = new LabeledStatement(statement);
      }
      target.continueTarget.resolveContinues(statement);
    }
    push(statement);
  }

  @override
  void endRethrowStatement(Token throwToken, Token endToken) {
    debugEvent("RethrowStatement");
    push(new ExpressionStatement(new Rethrow()));
  }

  @override
  void handleFinallyBlock(Token finallyKeyword) {
    debugEvent("FinallyBlock");
    // Do nothing, handled by [endTryStatement].
  }

  @override
  void endWhileStatement(Token whileKeyword, Token endToken) {
    debugEvent("WhileStatement");
    Statement body = popStatement();
    Expression condition = popForValue();
    JumpTarget continueTarget = exitContinueTarget();
    JumpTarget breakTarget = exitBreakTarget();
    if (continueTarget.hasUsers) {
      body = new LabeledStatement(body);
      continueTarget.resolveContinues(body);
    }
    Statement result = new WhileStatement(condition, body);
    if (breakTarget.hasUsers) {
      result = new LabeledStatement(result);
      breakTarget.resolveBreaks(result);
    }
    exitLoopOrSwitch(result);
  }

  @override
  void handleEmptyStatement(Token token) {
    debugEvent("EmptyStatement");
    push(new EmptyStatement());
  }

  @override
  void handleAssertStatement(Token assertKeyword, Token leftParenthesis,
      Token commaToken, Token rightParenthesis, Token semicolonToken) {
    debugEvent("AssertStatement");
    Expression message = popForValueIfNotNull(commaToken);
    Expression condition = popForValue();
    push(new AssertStatement(condition, message));
  }

  @override
  void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
    debugEvent("YieldStatement");
    push(new YieldStatement(popForValue(), isYieldStar: starToken != null));
  }

  @override
  void beginSwitchBlock(Token token) {
    debugEvent("beginSwitchBlock");
    enterLocalScope();
    enterSwitchScope();
    enterBreakTarget(token.charOffset);
  }

  @override
  void beginSwitchCase(int labelCount, int expressionCount, Token firstToken) {
    debugEvent("beginSwitchCase");
    List labelsAndExpressions = popList(labelCount + expressionCount);
    List<Label> labels = <Label>[];
    List<Expression> expressions = <Expression>[];
    if (labelsAndExpressions != null) {
      for (var labelOrExpression in labelsAndExpressions) {
        if (labelOrExpression is Label) {
          labels.add(labelOrExpression);
        } else {
          expressions.add(toValue(labelOrExpression));
        }
      }
    }
    assert(scope == switchScope);
    for (Label label in labels) {
      if (scope.hasLocalLabel(label.name)) {
        // TODO(ahe): Should validate this is a goto target and not duplicated.
        scope.claimLabel(label.name);
      } else {
        scope.declareLabel(label.name, createGotoTarget(firstToken.charOffset));
      }
    }
    push(expressions);
    push(labels);
    enterLocalScope();
  }

  @override
  void handleSwitchCase(
      int labelCount,
      int expressionCount,
      Token defaultKeyword,
      int statementCount,
      Token firstToken,
      Token endToken) {
    debugEvent("SwitchCase");
    Block block = popBlock(statementCount);
    exitLocalScope();
    List<Label> labels = pop();
    List<Expression> expressions = pop();
    push(new SwitchCase(expressions, block, isDefault: defaultKeyword != null)
      ..fileOffset = firstToken.charOffset);
    push(labels);
  }

  @override
  void endSwitchStatement(Token switchKeyword, Token endToken) {
    debugEvent("SwitchStatement");
    // Do nothing. Handled by [endSwitchBlock].
  }

  @override
  void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
    debugEvent("SwitchBlock");
    List<SwitchCase> cases =
        new List<SwitchCase>.filled(caseCount, null, growable: true);
    for (int i = caseCount - 1; i >= 0; i--) {
      List<Label> labels = pop();
      SwitchCase current = cases[i] = pop();
      for (Label label in labels) {
        JumpTarget target = switchScope.lookupLabel(label.name);
        if (target != null) {
          target.resolveGotos(current);
        }
      }
      // TODO(ahe): Validate that there's only one default and it's last.
    }
    JumpTarget target = exitBreakTarget();
    exitSwitchScope();
    exitLocalScope();
    Expression expression = popForValue();
    Statement result = new SwitchStatement(expression, cases);
    if (target.hasUsers) {
      result = new LabeledStatement(result);
      target.resolveBreaks(result);
    }
    exitLoopOrSwitch(result);
  }

  @override
  void handleCaseMatch(Token caseKeyword, Token colon) {
    debugEvent("CaseMatch");
    // Do nothing. Handled by [handleSwitchCase].
  }

  @override
  void handleBreakStatement(
      bool hasTarget, Token breakKeyword, Token endToken) {
    debugEvent("BreakStatement");
    var target = breakTarget;
    String name;
    if (hasTarget) {
      Identifier identifier = pop();
      name = identifier.name;
      target = scope.lookupLabel(identifier.name);
    }
    if (target == null && name == null) {
      push(compileTimeErrorInLoopOrSwitch = buildCompileTimeErrorStatement(
          "No target of break.", breakKeyword.charOffset));
    } else if (target == null ||
        target is! JumpTarget ||
        !target.isBreakTarget) {
      push(compileTimeErrorInLoopOrSwitch = buildCompileTimeErrorStatement(
          "Can't break to '$name'.", breakKeyword.next.charOffset));
    } else if (target.functionNestingLevel != functionNestingLevel) {
      push(compileTimeErrorInLoopOrSwitch = buildCompileTimeErrorStatement(
          "Can't break to '$name' in a different function.",
          breakKeyword.next.charOffset));
    } else {
      BreakStatement statement = new BreakStatement(null)
        ..fileOffset = breakKeyword.charOffset;
      target.addBreak(statement);
      push(statement);
    }
  }

  @override
  void handleContinueStatement(
      bool hasTarget, Token continueKeyword, Token endToken) {
    debugEvent("ContinueStatement");
    var target = continueTarget;
    String name;
    if (hasTarget) {
      Identifier identifier = pop();
      name = identifier.name;
      target = scope.lookupLabel(identifier.name);
      if (target != null && target is! JumpTarget) {
        push(compileTimeErrorInLoopOrSwitch = buildCompileTimeErrorStatement(
            "Target of continue must be a label.", continueKeyword.charOffset));
        return;
      }
      if (target == null) {
        if (switchScope == null) {
          push(buildCompileTimeErrorStatement(
              "Can't find label '$name'.", continueKeyword.next.charOffset));
          return;
        }
        switchScope.forwardDeclareLabel(
            identifier.name, target = createGotoTarget(identifier.fileOffset));
      }
      if (target.isGotoTarget &&
          target.functionNestingLevel == functionNestingLevel) {
        ContinueSwitchStatement statement = new ContinueSwitchStatement(null);
        target.addGoto(statement);
        push(statement);
        return;
      }
    }
    if (target == null) {
      push(compileTimeErrorInLoopOrSwitch = buildCompileTimeErrorStatement(
          "No target of continue.", continueKeyword.charOffset));
    } else if (!target.isContinueTarget) {
      push(compileTimeErrorInLoopOrSwitch = buildCompileTimeErrorStatement(
          "Can't continue at '$name'.", continueKeyword.next.charOffset));
    } else if (target.functionNestingLevel != functionNestingLevel) {
      push(compileTimeErrorInLoopOrSwitch = buildCompileTimeErrorStatement(
          "Can't continue at '$name' in a different function.",
          continueKeyword.next.charOffset));
    } else {
      BreakStatement statement = new BreakStatement(null)
        ..fileOffset = continueKeyword.charOffset;
      target.addContinue(statement);
      push(statement);
    }
  }

  @override
  void endTypeVariable(Token token, Token extendsOrSuper) {
    debugEvent("TypeVariable");
    // TODO(ahe): Do not discard these when enabling generic method syntax.
    pop(); // Bound.
    pop(); // Name.
  }

  @override
  void endTypeVariables(int count, Token beginToken, Token endToken) {
    debugEvent("TypeVariables");
    // TODO(ahe): Implement this when enabling generic method syntax.
    push(NullValue.TypeVariables);
  }

  @override
  void handleModifier(Token token) {
    debugEvent("Modifier");
    // TODO(ahe): Copied from outline_builder.dart.
    push(new Modifier.fromString(token.stringValue));
  }

  @override
  void handleModifiers(int count) {
    debugEvent("Modifiers");
    // TODO(ahe): Copied from outline_builder.dart.
    push(popList(count) ?? NullValue.Modifiers);
  }

  @override
  void handleRecoverableError(Token token, ErrorKind kind, Map arguments) {
    bool silent = hasParserError;
    super.handleRecoverableError(token, kind, arguments);
    addCompileTimeError(recoverableErrors.last.beginOffset,
        '${recoverableErrors.last.kind} $arguments',
        silent: silent);
  }

  @override
  Token handleUnrecoverableError(Token token, ErrorKind kind, Map arguments) {
    if (isDartLibrary && kind == ErrorKind.ExpectedFunctionBody) {
      Token recover = skipNativeClause(token);
      if (recover != null) return recover;
    } else if (kind == ErrorKind.UnexpectedToken) {
      String expected = arguments["expected"];
      const List<String> trailing = const <String>[")", "}", ";", ","];
      if (trailing.contains(token.stringValue) && trailing.contains(expected)) {
        arguments.putIfAbsent("actual", () => token.lexeme);
        handleRecoverableError(token, ErrorKind.ExpectedButGot, arguments);
        return newSyntheticToken(token);
      }
    }
    return super.handleUnrecoverableError(token, kind, arguments);
  }

  @override
  Expression buildCompileTimeError(error, [int charOffset = -1]) {
    addCompileTimeError(charOffset, error);
    String message = formatUnexpected(uri, charOffset, error);
    Builder constructor = library.loader.getCompileTimeError();
    return new Throw(buildStaticInvocation(constructor.target,
        new Arguments(<Expression>[new StringLiteral(message)]),
        isConst: false)); // TODO(ahe): Make this const.
  }

  Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) {
    return new ExpressionStatement(buildCompileTimeError(error, charOffset));
  }

  @override
  Initializer buildCompileTimeErrorIntializer(error, [int charOffset = -1]) {
    return new LocalInitializer(new VariableDeclaration.forValue(
        buildCompileTimeError(error, charOffset)));
  }

  @override
  Expression buildProblemExpression(Builder builder, String name) {
    if (builder is AmbiguousBuilder) {
      return buildCompileTimeError("Duplicated named: '$name'.");
    } else if (builder is AccessErrorBuilder) {
      return buildCompileTimeError("Access error: '$name'.");
    } else {
      return internalError("Unhandled: ${builder.runtimeType}");
    }
  }

  @override
  void handleOperator(Token token) {
    debugEvent("Operator");
    push(new Operator(token.stringValue)..fileOffset = token.charOffset);
  }

  @override
  void handleSymbolVoid(Token token) {
    logEvent("SymbolVoid");
  }

  dynamic addCompileTimeError(int charOffset, String message,
      {bool silent: false}) {
    return library.addCompileTimeError(charOffset, message, fileUri: uri);
  }

  @override
  void handleInvalidFunctionBody(Token token) {
    if (member.isNative) {
      push(NullValue.FunctionBody);
    } else {
      push(new Block(<Statement>[new InvalidStatement()]));
    }
  }

  @override
  void debugEvent(String name) {
    // printEvent(name);
  }
}

// TODO(ahe): Shouldn't need to be an expression.
class UnresolvedIdentifier extends InvalidExpression {
  final Name name;

  UnresolvedIdentifier(this.name);

  String toString() => "unresolved-identifier($name)";
}

// TODO(ahe): Shouldn't need to be an expression.
class Identifier extends InvalidExpression {
  final String name;

  Identifier(this.name);

  Expression get initializer => null;

  String toString() => "identifier($name)";
}

// TODO(ahe): Shouldn't need to be an expression.
class Operator extends InvalidExpression {
  final String name;

  Operator(this.name);

  String toString() => "operator($name)";
}

class InitializedIdentifier extends Identifier {
  final Expression initializer;

  InitializedIdentifier(String name, this.initializer) : super(name);

  String toString() => "initialized-identifier($name, $initializer)";
}

// TODO(ahe): Shouldn't need to be an expression.
class Label extends InvalidExpression {
  String name;

  Label(this.name);

  String toString() => "label($name)";
}

class CascadeReceiver extends Let {
  Let nextCascade;

  CascadeReceiver(VariableDeclaration variable)
      : super(
            variable,
            makeLet(new VariableDeclaration.forValue(new InvalidExpression()),
                new VariableGet(variable))) {
    nextCascade = body;
  }

  void extend() {
    assert(nextCascade.variable.initializer is! InvalidExpression);
    Let newCascade = makeLet(
        new VariableDeclaration.forValue(new InvalidExpression()),
        nextCascade.body);
    nextCascade.body = newCascade;
    newCascade.parent = nextCascade;
    nextCascade = newCascade;
  }

  void finalize(Expression expression) {
    assert(nextCascade.variable.initializer is InvalidExpression);
    nextCascade.variable.initializer = expression;
    expression.parent = nextCascade.variable;
  }
}

abstract class ContextAccessor extends BuilderAccessor {
  final BuilderHelper helper;

  final int charOffset;

  final BuilderAccessor accessor;

  ContextAccessor(this.helper, this.charOffset, this.accessor);

  String get plainNameForRead => internalError("Unsupported operation.");

  Expression doInvocation(int charOffset, Arguments arguments) {
    print("$uri:$charOffset: Internal error: Unhandled: ${runtimeType}");
    return internalError("Unhandled: ${runtimeType}");
  }

  Expression buildSimpleRead();

  Expression buildForEffect();

  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return makeInvalidWrite(value);
  }

  Expression buildNullAwareAssignment(Expression value, DartType type,
      {bool voidContext: false}) {
    return makeInvalidWrite(value);
  }

  Expression buildCompoundAssignment(
      Name binaryOperator, Expression value, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return makeInvalidWrite(value);
  }

  Expression buildPrefixIncrement(Name binaryOperator, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return makeInvalidWrite(null);
  }

  Expression buildPostfixIncrement(Name binaryOperator, int charOffset,
      {bool voidContext: false, Procedure interfaceTarget}) {
    return makeInvalidWrite(null);
  }

  makeInvalidRead() => internalError("not supported");

  Expression makeInvalidWrite(Expression value) {
    return helper.buildCompileTimeError(
        "Can't be used as left-hand side of assignment.", charOffset);
  }
}

class DelayedAssignment extends ContextAccessor {
  final Expression value;

  final String assignmentOperator;

  DelayedAssignment(BuilderHelper helper, int charOffset,
      BuilderAccessor accessor, this.value, this.assignmentOperator)
      : super(helper, charOffset, accessor);

  Expression buildSimpleRead() {
    return handleAssignment(false);
  }

  Expression buildForEffect() {
    return handleAssignment(true);
  }

  Expression handleAssignment(bool voidContext) {
    if (identical("=", assignmentOperator)) {
      return accessor.buildAssignment(value, voidContext: voidContext);
    } else if (identical("+=", assignmentOperator)) {
      return accessor.buildCompoundAssignment(plusName, value, charOffset,
          voidContext: voidContext);
    } else if (identical("-=", assignmentOperator)) {
      return accessor.buildCompoundAssignment(minusName, value, charOffset,
          voidContext: voidContext);
    } else if (identical("*=", assignmentOperator)) {
      return accessor.buildCompoundAssignment(multiplyName, value, charOffset,
          voidContext: voidContext);
    } else if (identical("%=", assignmentOperator)) {
      return accessor.buildCompoundAssignment(percentName, value, charOffset,
          voidContext: voidContext);
    } else if (identical("&=", assignmentOperator)) {
      return accessor.buildCompoundAssignment(ampersandName, value, charOffset,
          voidContext: voidContext);
    } else if (identical("/=", assignmentOperator)) {
      return accessor.buildCompoundAssignment(divisionName, value, charOffset,
          voidContext: voidContext);
    } else if (identical("<<=", assignmentOperator)) {
      return accessor.buildCompoundAssignment(leftShiftName, value, charOffset,
          voidContext: voidContext);
    } else if (identical(">>=", assignmentOperator)) {
      return accessor.buildCompoundAssignment(rightShiftName, value, charOffset,
          voidContext: voidContext);
    } else if (identical("??=", assignmentOperator)) {
      return accessor.buildNullAwareAssignment(value, const DynamicType(),
          voidContext: voidContext);
    } else if (identical("^=", assignmentOperator)) {
      return accessor.buildCompoundAssignment(caretName, value, charOffset,
          voidContext: voidContext);
    } else if (identical("|=", assignmentOperator)) {
      return accessor.buildCompoundAssignment(barName, value, charOffset,
          voidContext: voidContext);
    } else if (identical("~/=", assignmentOperator)) {
      return accessor.buildCompoundAssignment(mustacheName, value, charOffset,
          voidContext: voidContext);
    } else {
      return internalError("Unhandled: $assignmentOperator");
    }
  }

  Initializer buildFieldInitializer(
      Map<String, FieldInitializer> initializers) {
    if (!identical("=", assignmentOperator) ||
        !accessor.isThisPropertyAccessor) {
      return accessor.buildFieldInitializer(initializers);
    }
    String name = accessor.plainNameForRead;
    FieldInitializer initializer = initializers[name];
    if (initializer != null && initializer.value == null) {
      initializers.remove(name);
      initializer.value = value..parent = initializer;
      return initializer;
    }
    return accessor.buildFieldInitializer(initializers);
  }
}

class DelayedPostfixIncrement extends ContextAccessor {
  final Name binaryOperator;

  final Procedure interfaceTarget;

  DelayedPostfixIncrement(BuilderHelper helper, int charOffset,
      BuilderAccessor accessor, this.binaryOperator, this.interfaceTarget)
      : super(helper, charOffset, accessor);

  Expression buildSimpleRead() {
    return accessor.buildPostfixIncrement(binaryOperator, charOffset,
        voidContext: false, interfaceTarget: interfaceTarget);
  }

  Expression buildForEffect() {
    return accessor.buildPostfixIncrement(binaryOperator, charOffset,
        voidContext: true, interfaceTarget: interfaceTarget);
  }
}

class JumpTarget extends Builder {
  final List<Statement> users = <Statement>[];

  final JumpTargetKind kind;

  final int functionNestingLevel;

  JumpTarget(this.kind, this.functionNestingLevel, MemberBuilder member,
      int charOffset)
      : super(member, charOffset, member.fileUri);

  bool get isBreakTarget => kind == JumpTargetKind.Break;

  bool get isContinueTarget => kind == JumpTargetKind.Continue;

  bool get isGotoTarget => kind == JumpTargetKind.Goto;

  bool get hasUsers => users.isNotEmpty;

  void addBreak(BreakStatement statement) {
    assert(isBreakTarget);
    users.add(statement);
  }

  void addContinue(BreakStatement statement) {
    assert(isContinueTarget);
    users.add(statement);
  }

  void addGoto(ContinueSwitchStatement statement) {
    assert(isGotoTarget);
    users.add(statement);
  }

  void resolveBreaks(LabeledStatement target) {
    assert(isBreakTarget);
    for (BreakStatement user in users) {
      user.target = target;
    }
    users.clear();
  }

  void resolveContinues(LabeledStatement target) {
    assert(isContinueTarget);
    for (BreakStatement user in users) {
      user.target = target;
    }
    users.clear();
  }

  void resolveGotos(SwitchCase target) {
    assert(isGotoTarget);
    for (ContinueSwitchStatement user in users) {
      user.target = target;
    }
    users.clear();
  }
}

class LabelTarget extends Builder implements JumpTarget {
  final JumpTarget breakTarget;

  final JumpTarget continueTarget;

  final int functionNestingLevel;

  LabelTarget(MemberBuilder member, this.functionNestingLevel, int charOffset)
      : breakTarget = new JumpTarget(
            JumpTargetKind.Break, functionNestingLevel, member, charOffset),
        continueTarget = new JumpTarget(
            JumpTargetKind.Continue, functionNestingLevel, member, charOffset),
        super(member, charOffset, member.fileUri);

  bool get hasUsers => breakTarget.hasUsers || continueTarget.hasUsers;

  List<Statement> get users => internalError("Unsupported operation.");

  JumpTargetKind get kind => internalError("Unsupported operation.");

  bool get isBreakTarget => true;

  bool get isContinueTarget => true;

  bool get isGotoTarget => false;

  void addBreak(BreakStatement statement) {
    breakTarget.addBreak(statement);
  }

  void addContinue(BreakStatement statement) {
    continueTarget.addContinue(statement);
  }

  void addGoto(ContinueSwitchStatement statement) {
    internalError("Unsupported operation.");
  }

  void resolveBreaks(LabeledStatement target) {
    breakTarget.resolveBreaks(target);
  }

  void resolveContinues(LabeledStatement target) {
    continueTarget.resolveContinues(target);
  }

  void resolveGotos(SwitchCase target) {
    internalError("Unsupported operation.");
  }
}

class OptionalFormals {
  final FormalParameterType kind;

  final List<VariableDeclaration> formals;

  OptionalFormals(this.kind, this.formals);
}

class FormalParameters {
  final List<VariableDeclaration> required;
  final OptionalFormals optional;

  FormalParameters(this.required, this.optional);

  FunctionNode addToFunction(FunctionNode function) {
    function.requiredParameterCount = required.length;
    function.positionalParameters.addAll(required);
    if (optional != null) {
      if (optional.kind.isPositional) {
        function.positionalParameters.addAll(optional.formals);
      } else {
        function.namedParameters.addAll(optional.formals);
        setParents(function.namedParameters, function);
      }
    }
    setParents(function.positionalParameters, function);
    return function;
  }

  FunctionType toFunctionType(DartType returnType) {
    returnType ??= const DynamicType();
    int requiredParameterCount = required.length;
    List<DartType> positionalParameters = <DartType>[];
    List<NamedType> namedParameters = const <NamedType>[];
    for (VariableDeclaration parameter in required) {
      positionalParameters.add(parameter.type);
    }
    if (optional != null) {
      if (optional.kind.isPositional) {
        for (VariableDeclaration parameter in optional.formals) {
          positionalParameters.add(parameter.type);
        }
      } else {
        namedParameters = <NamedType>[];
        for (VariableDeclaration parameter in optional.formals) {
          namedParameters.add(new NamedType(parameter.name, parameter.type));
        }
        namedParameters.sort();
      }
    }
    return new FunctionType(positionalParameters, returnType,
        namedParameters: namedParameters,
        requiredParameterCount: requiredParameterCount);
  }

  Scope computeFormalParameterScope(Scope parent, Builder builder) {
    if (required.length == 0 && optional == null) return parent;
    Map<String, Builder> local = <String, Builder>{};
    for (VariableDeclaration parameter in required) {
      local[parameter.name] =
          new KernelVariableBuilder(parameter, builder, builder.fileUri);
    }
    if (optional != null) {
      for (VariableDeclaration parameter in optional.formals) {
        local[parameter.name] =
            new KernelVariableBuilder(parameter, builder, builder.fileUri);
      }
    }
    return new Scope(local, parent, isModifiable: false);
  }
}

/// Returns a block like this:
///
///     {
///       statement;
///       body;
///     }
///
/// If [body] is a [Block], it's returned with [statement] prepended to it.
Block combineStatements(Statement statement, Statement body) {
  if (body is Block) {
    body.statements.insert(0, statement);
    statement.parent = body;
    return body;
  } else {
    return new Block(<Statement>[statement, body]);
  }
}

String debugName(String className, String name, [String prefix]) {
  String result = name.isEmpty ? className : "$className.$name";
  return prefix == null ? result : "$prefix.result";
}

String getNodeName(Object node) {
  if (node is Identifier) {
    return node.name;
  } else if (node is UnresolvedIdentifier) {
    return node.name.name;
  } else if (node is TypeDeclarationBuilder) {
    return node.name;
  } else if (node is PrefixBuilder) {
    return node.name;
  } else if (node is ThisAccessor) {
    return node.isSuper ? "super" : "this";
  } else if (node is BuilderAccessor) {
    return node.plainNameForRead;
  } else {
    return internalError("Unhandled: ${node.runtimeType}");
  }
}
