// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

library dart2js.parser.node_listener;

import 'package:front_end/src/fasta/parser.dart'
    show FormalParameterKind, IdentifierContext, MemberKind;
import 'package:front_end/src/fasta/scanner.dart' show Token;
import 'package:front_end/src/scanner/token.dart' show TokenType;

import '../common.dart';
import '../elements/elements.dart' show CompilationUnitElement;
import '../tree/tree.dart';
import '../util/util.dart' show Link;
import 'element_listener.dart' show ElementListener, ScannerOptions;

import 'package:front_end/src/fasta/parser.dart' as fasta show Assert;

class NodeListener extends ElementListener {
  int invalidTopLevelDeclarationCount = 0;
  int invalidMemberCount = 0;

  NodeListener(ScannerOptions scannerOptions, DiagnosticReporter reporter,
      CompilationUnitElement element)
      : super(scannerOptions, reporter, element, null);

  @override
  void addLibraryTag(LibraryTag tag) {
    pushNode(tag);
  }

  @override
  void addPartOfTag(PartOf tag) {
    pushNode(tag);
  }

  @override
  void endLibraryName(Token libraryKeyword, Token semicolon) {
    Expression name = popNode();
    pushNode(new LibraryName(
        libraryKeyword,
        name,
        // TODO(sigmund): Import AST nodes have pointers to MetadataAnnotation
        // (element) instead of Metatada (node).
        null));
  }

  @override
  void endImport(Token importKeyword, Token semicolon) {
    NodeList combinators = popNode();
    Flag flag = popNode();
    bool isDeferred = flag == Flag.TRUE;
    Identifier prefix = popNode();
    NodeList conditionalUris = popNode();
    StringNode uri = popLiteralString();
    pushNode(new Import(
        importKeyword,
        uri,
        conditionalUris,
        prefix,
        combinators,
        // TODO(sigmund): Import AST nodes have pointers to MetadataAnnotation
        // (element) instead of Metatada (node).
        null,
        isDeferred: isDeferred));
  }

  @override
  void endExport(Token exportKeyword, Token semicolon) {
    NodeList combinators = popNode();
    NodeList conditionalUris = popNode();
    StringNode uri = popLiteralString();
    pushNode(new Export(
        exportKeyword,
        uri,
        conditionalUris,
        combinators,
        // TODO(sigmund): Import AST nodes have pointers to MetadataAnnotation
        // (element) instead of Metatada (node).
        null));
  }

  @override
  void endPart(Token partKeyword, Token semicolon) {
    StringNode uri = popLiteralString();
    pushNode(new Part(
        partKeyword,
        uri,
        // TODO(sigmund): Import AST nodes have pointers to MetadataAnnotation
        // (element) instead of Metatada (node).
        null));
  }

  @override
  void endPartOf(
      Token partKeyword, Token ofKeyword, Token semicolon, bool hasName) {
    Expression name = popNode(); // name
    pushNode(new PartOf(
        partKeyword,
        name,
        // TODO(sigmund): Import AST nodes have pointers to MetadataAnnotation
        // (element) instead of Metatada (node).
        null));
  }

  @override
  void handleClassExtends(Token extendsKeyword) {
    pushNode(new TokenNode(extendsKeyword));
  }

  @override
  void handleClassImplements(Token implementsKeyword, int interfacesCount) {
    pushNode(makeNodeList(interfacesCount, implementsKeyword, null, ","));
  }

  @override
  void handleRecoverClassHeader() {
    popNode(); // interfaces
    popNode(); // extendsNode
    popNode(); // supertype
  }

  @override
  void endClassDeclaration(Token beginToken, Token endToken) {
    NodeList body = popNode();
    NodeList interfaces = popNode();
    TokenNode extendsNode = popNode();
    Node supertype = popNode();
    NodeList typeParameters = popNode();
    Identifier name = popNode();
    Modifiers modifiers = popNode();
    // TODO(danrubel): can we remove the extends keyword from ClassNode ?
    pushNode(new ClassNode(modifiers, name, typeParameters, supertype,
        interfaces, beginToken, extendsNode.token, body, endToken));
  }

  @override
  void handleInvalidTopLevelDeclaration(Token endToken) {
    ++invalidTopLevelDeclarationCount;
  }

  @override
  void endTopLevelDeclaration(Token token) {
    // TODO(sigmund): consider moving metadata into each declaration
    // element instead.
    Node node = popNode(); // top-level declaration
    popNode(); // Discard metadata
    pushNode(node);
    super.endTopLevelDeclaration(token);
  }

  @override
  void beginCompilationUnit(Token token) {
    invalidTopLevelDeclarationCount = 0;
  }

  @override
  void endCompilationUnit(int count, Token token) {
    pushNode(makeNodeList(
        count - invalidTopLevelDeclarationCount, null, null, '\n'));
  }

  @override
  void endFunctionTypeAlias(
      Token typedefKeyword, Token equals, Token endToken) {
    bool isGeneralizedTypeAlias;
    NodeList templateParameters;
    TypeAnnotation returnType;
    Identifier name;
    NodeList typeParameters;
    NodeList formals;
    if (equals == null) {
      isGeneralizedTypeAlias = false;
      formals = popNode();
      templateParameters = popNode();
      name = popNode();
      returnType = popNode();
    } else {
      // TODO(floitsch): keep using the `FunctionTypeAnnotation' node.
      isGeneralizedTypeAlias = true;
      Node type = popNode();
      if (type.asFunctionTypeAnnotation() == null) {
        // TODO(floitsch): The parser should diagnose this problem, not
        // this listener.
        // However, this problem goes away, when we allow aliases for
        // non-function types too.
        reportFatalError(type, 'Expected a function type.');
      }
      FunctionTypeAnnotation functionType = type;
      templateParameters = popNode();
      name = popNode();
      returnType = functionType.returnType;
      typeParameters = functionType.typeParameters;
      formals = functionType.formals;
    }
    pushNode(new Typedef(isGeneralizedTypeAlias, templateParameters, returnType,
        name, typeParameters, formals, typedefKeyword, endToken));
  }

  void handleNoName(Token token) {
    pushNode(null);
  }

  @override
  void endFunctionType(Token functionToken, Token endToken) {
    NodeList formals = popNode();
    TypeAnnotation returnType = popNode();
    NodeList typeParameters = popNode();
    pushNode(new FunctionTypeAnnotation(
        returnType, functionToken, typeParameters, formals));
  }

  @override
  void endNamedMixinApplication(Token beginToken, Token classKeyword,
      Token equals, Token implementsKeyword, Token endToken) {
    NodeList interfaces = (implementsKeyword != null) ? popNode() : null;
    Node mixinApplication = popNode();
    NodeList typeParameters = popNode();
    Identifier name = popNode();
    Modifiers modifiers = popNode();
    pushNode(new NamedMixinApplication(name, typeParameters, modifiers,
        mixinApplication, interfaces, beginToken, endToken));
  }

  @override
  void endEnum(Token enumKeyword, Token leftBrace, int count) {
    NodeList names = makeNodeList(count, leftBrace, leftBrace?.endGroup, ",");
    Identifier name = popNode();
    pushNode(new Enum(enumKeyword, name, names));
  }

  @override
  void endClassBody(int memberCount, Token beginToken, Token endToken) {
    pushNode(makeNodeList(
        memberCount - invalidMemberCount, beginToken, endToken, null));
    invalidMemberCount = 0;
  }

  @override
  void endTopLevelFields(int count, Token beginToken, Token endToken) {
    NodeList variables = makeNodeList(count, null, endToken, ",");
    TypeAnnotation type = popNode();
    Modifiers modifiers = popNode();
    pushNode(new VariableDefinitions(type, modifiers, variables));
  }

  @override
  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
    Statement body = popNode();
    AsyncModifier asyncModifier = popNode();
    NodeList formals = popNode();
    NodeList typeVariables = popNode();
    Identifier name = popNode();
    TypeAnnotation type = popNode();
    Modifiers modifiers = popNode();
    pushNode(new FunctionExpression(name, typeVariables, formals, body, type,
        modifiers, null, getOrSet, asyncModifier));
  }

  @override
  void endFormalParameter(Token thisKeyword, Token periodAfterThis,
      Token nameToken, FormalParameterKind kind, MemberKind memberKind) {
    Expression name = popNode();
    if (thisKeyword != null) {
      Identifier thisIdentifier = new Identifier(thisKeyword);
      if (name.asSend() == null) {
        name = new Send(thisIdentifier, name);
      } else {
        name = name.asSend().copyWithReceiver(thisIdentifier, false);
      }
    }
    TypeAnnotation type = popNode();
    Modifiers modifiers = popNode();
    NodeList metadata = popNode();
    pushNode(new VariableDefinitions.forParameter(
        metadata, type, modifiers, new NodeList.singleton(name)));
  }

  @override
  void endFormalParameters(
      int count, Token beginToken, Token endToken, MemberKind kind) {
    pushNode(makeNodeList(count, beginToken, endToken, ","));
  }

  @override
  void handleNoFormalParameters(Token token, MemberKind kind) {
    pushNode(null);
  }

  @override
  void endArguments(int count, Token beginToken, Token endToken) {
    pushNode(makeNodeList(count, beginToken, endToken, ","));
  }

  @override
  void handleNoArguments(Token token) {
    pushNode(null);
  }

  @override
  void endConstructorReference(
      Token start, Token periodBeforeName, Token endToken) {
    Identifier name = null;
    if (periodBeforeName != null) {
      name = popNode();
    }
    NodeList typeArguments = popNode();
    Node classReference = popNode();
    if (typeArguments != null) {
      classReference = new NominalTypeAnnotation(classReference, typeArguments);
    } else {
      Identifier identifier = classReference.asIdentifier();
      Send send = classReference.asSend();
      if (identifier != null) {
        // TODO(ahe): Should be:
        // classReference = new Send(null, identifier);
        classReference = identifier;
      } else if (send != null) {
        classReference = send;
      } else {
        internalError(node: classReference);
      }
    }
    Node constructor = classReference;
    if (name != null) {
      // Either typeName<args>.name or x.y.name.
      constructor = new Send(classReference, name);
    }
    pushNode(constructor);
  }

  @override
  void endRedirectingFactoryBody(Token beginToken, Token endToken) {
    pushNode(new RedirectingFactoryBody(beginToken, endToken, popNode()));
  }

  @override
  void handleNativeFunctionBody(Token nativeToken, Token semicolon) {
    pushNode(new Return(nativeToken, semicolon, nativeName));
  }

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

  void handleExpressionFunctionBody(Token arrowToken, Token endToken) {
    endReturnStatement(true, arrowToken, endToken);
  }

  @override
  void endReturnStatement(
      bool hasExpression, Token beginToken, Token endToken) {
    Expression expression = hasExpression ? popNode() : null;
    pushNode(new Return(beginToken, endToken, expression));
  }

  @override
  void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
    Expression expression = popNode();
    pushNode(new Yield(yieldToken, starToken, expression, endToken));
  }

  @override
  void endExpressionStatement(Token token) {
    pushNode(new ExpressionStatement(popNode(), token));
  }

  void handleOnError(Token token, var errorInformation) {
    reporter.internalError(reporter.spanFromToken(token),
        "'${token.lexeme}': ${errorInformation}");
  }

  @override
  void handleLiteralInt(Token token) {
    pushNode(new LiteralInt(token, (t, e) => handleOnError(t, e)));
  }

  @override
  void handleLiteralDouble(Token token) {
    pushNode(new LiteralDouble(token, (t, e) => handleOnError(t, e)));
  }

  @override
  void handleLiteralBool(Token token) {
    pushNode(new LiteralBool(token, (t, e) => handleOnError(t, e)));
  }

  @override
  void handleLiteralNull(Token token) {
    pushNode(new LiteralNull(token));
  }

  @override
  void endLiteralSymbol(Token hashToken, int identifierCount) {
    NodeList identifiers = makeNodeList(identifierCount, null, null, '.');
    pushNode(new LiteralSymbol(hashToken, identifiers));
  }

  @override
  void endBinaryExpression(Token token) {
    Node argument = popNode();
    Node receiver = popNode();
    String tokenString = token.stringValue;
    if (identical(tokenString, '.') ||
        identical(tokenString, '..') ||
        identical(tokenString, '?.')) {
      Send argumentSend = argument.asSend();
      if (argumentSend == null) {
        // TODO(ahe): The parser should diagnose this problem, not
        // this listener.
        reportFatalError(
            reporter.spanFromSpannable(argument), "Expected an identifier.");
      }
      if (argumentSend.receiver != null) internalError(node: argument);
      if (argument is SendSet) internalError(node: argument);
      pushNode(argument
          .asSend()
          .copyWithReceiver(receiver, identical(tokenString, '?.')));
    } else {
      NodeList arguments = new NodeList.singleton(argument);
      pushNode(new Send(receiver, new Operator(token), arguments));
    }
    if (identical(tokenString, '===')) {
      reporter.reportErrorMessage(reporter.spanFromToken(token),
          MessageKind.UNSUPPORTED_EQ_EQ_EQ, {'lhs': receiver, 'rhs': argument});
    }
    if (identical(tokenString, '!==')) {
      reporter.reportErrorMessage(
          reporter.spanFromToken(token),
          MessageKind.UNSUPPORTED_BANG_EQ_EQ,
          {'lhs': receiver, 'rhs': argument});
    }
  }

  @override
  void beginCascade(Token token) {
    pushNode(new CascadeReceiver(popNode(), token));
  }

  @override
  void endCascade() {
    pushNode(new Cascade(popNode()));
  }

  @override
  void handleAsOperator(Token operator, Token endToken) {
    TypeAnnotation type = popNode();
    Expression expression = popNode();
    NodeList arguments = new NodeList.singleton(type);
    pushNode(new Send(expression, new Operator(operator), arguments));
  }

  @override
  void handleAssignmentExpression(Token token) {
    Node arg = popNode();
    Node node = popNode();
    Send send = node.asSend();
    if (send == null || !(send.isPropertyAccess || send.isIndex)) {
      reportNotAssignable(node);
    }
    var tokenString = token.stringValue;
    if (tokenString == '||=' || tokenString == '&&=') {
      reporter.reportErrorMessage(reporter.spanFromToken(token),
          MessageKind.UNSUPPORTED_OPERATOR, {'operator': tokenString});
      pushNode(arg);
      return;
    }
    if (send.asSendSet() != null) internalError(node: send);
    NodeList arguments;
    if (send.isIndex) {
      Link<Node> link = const Link<Node>().prepend(arg);
      link = link.prepend(send.arguments.head);
      arguments = new NodeList(null, link);
    } else {
      arguments = new NodeList.singleton(arg);
    }
    Operator op = new Operator(token);
    pushNode(new SendSet(
        send.receiver, send.selector, op, arguments, send.isConditional));
  }

  void reportNotAssignable(Node node) {
    // TODO(ahe): The parser should diagnose this problem, not this
    // listener.
    reportFatalError(reporter.spanFromSpannable(node), "Not assignable.");
  }

  @override
  void endConditionalExpression(Token question, Token colon) {
    Node elseExpression = popNode();
    Node thenExpression = popNode();
    Node condition = popNode();
    pushNode(new Conditional(
        condition, thenExpression, elseExpression, question, colon));
  }

  @override
  void handleSend(Token beginToken, Token endToken) {
    NodeList arguments = popNode();
    NodeList typeArguments = popNode();
    Node selector = popNode();
    // TODO(ahe): Handle receiver.
    pushNode(new Send(null, selector, arguments, typeArguments));
  }

  @override
  void endBlockFunctionBody(int count, Token beginToken, Token endToken) {
    if (count == 0 && beginToken == null) {
      pushNode(new EmptyStatement(endToken));
    } else {
      pushNode(new Block(makeNodeList(count, beginToken, endToken, null)));
    }
  }

  @override
  void handleAsyncModifier(Token asyncToken, Token starToken) {
    if (asyncToken != null) {
      pushNode(new AsyncModifier(asyncToken, starToken));
    } else {
      pushNode(null);
    }
  }

  @override
  void handleFunctionBodySkipped(Token token, bool isExpressionBody) {
    pushNode(new Block(new NodeList.empty()));
  }

  @override
  void handleNativeFunctionBodyIgnored(Token nativeToken, Token semicolon) {}

  @override
  void handleNativeFunctionBodySkipped(Token nativeToken, Token semicolon) {
    pushNode(new Block(new NodeList.empty()));
  }

  @override
  void handleNoFunctionBody(Token token) {
    pushNode(new EmptyStatement(token));
  }

  @override
  void endNamedFunctionExpression(Token endToken) {
    Statement body = popNode();
    AsyncModifier asyncModifier = popNode();
    NodeList initializers = popNode();
    NodeList formals = popNode();
    // The name can be an identifier or a send in case of named constructors.
    Expression name = popNode();
    TypeAnnotation type = popNode();
    Modifiers modifiers = popNode();
    NodeList typeVariables = popNode();
    pushNode(new FunctionExpression(name, typeVariables, formals, body, type,
        modifiers, initializers, null, asyncModifier));
  }

  @override
  void endLocalFunctionDeclaration(Token endToken) {
    Statement body = popNode();
    AsyncModifier asyncModifier = popNode();
    NodeList initializers = popNode();
    NodeList formals = popNode();
    // The name can be an identifier or a send in case of named constructors.
    Expression name = popNode();
    TypeAnnotation type = popNode();
    Modifiers modifiers = popNode();
    NodeList typeVariables = popNode();
    pushNode(new FunctionDeclaration(new FunctionExpression(name, typeVariables,
        formals, body, type, modifiers, initializers, null, asyncModifier)));
  }

  @override
  void beginVariablesDeclaration(Token token, Token varFinalOrConst) {
    if (varFinalOrConst == null) {
      pushNode(Modifiers.EMPTY);
    } else {
      Link<Node> nodes =
          const Link<Node>().prepend(new Identifier(varFinalOrConst));
      pushNode(new Modifiers(new NodeList(null, nodes, null, ' ')));
    }
  }

  @override
  void endVariablesDeclaration(int count, Token endToken) {
    // TODO(ahe): Pick one name for this concept, either
    // VariablesDeclaration or VariableDefinitions.
    NodeList variables = makeNodeList(count, null, endToken, ",");
    Modifiers modifiers = popNode();
    TypeAnnotation type = popNode();
    popNode();
    pushNode(new VariableDefinitions(type, modifiers, variables));
  }

  @override
  void endVariableInitializer(Token assignmentOperator) {
    Expression initializer = popNode();
    NodeList arguments =
        initializer == null ? null : new NodeList.singleton(initializer);
    Expression name = popNode();
    Operator op = new Operator(assignmentOperator);
    pushNode(new SendSet(null, name, op, arguments));
  }

  @override
  void endFieldInitializer(Token assignmentOperator, Token token) {
    endVariableInitializer(assignmentOperator);
  }

  @override
  void endIfStatement(Token ifToken, Token elseToken) {
    Statement elsePart = (elseToken == null) ? null : popNode();
    Statement thenPart = popNode();
    ParenthesizedExpression condition = popNode();
    pushNode(new If(condition, thenPart, elsePart, ifToken, elseToken));
  }

  @override
  void endForStatement(Token forKeyword, Token leftParen, Token leftSeparator,
      int updateExpressionCount, Token endToken) {
    Statement body = popNode();
    NodeList updates = makeNodeList(updateExpressionCount, null, null, ',');
    Statement condition = popNode();
    Node initializer = popNode();
    pushNode(new For(initializer, condition, updates, body, forKeyword));
  }

  @override
  void handleNoExpression(Token token) {
    pushNode(null);
  }

  @override
  void endDoWhileStatement(
      Token doKeyword, Token whileKeyword, Token endToken) {
    Expression condition = popNode();
    Statement body = popNode();
    pushNode(new DoWhile(body, condition, doKeyword, whileKeyword, endToken));
  }

  @override
  void endWhileStatement(Token whileKeyword, Token endToken) {
    Statement body = popNode();
    Expression condition = popNode();
    pushNode(new While(condition, body, whileKeyword));
  }

  @override
  void endBlock(int count, Token beginToken, Token endToken) {
    pushNode(new Block(makeNodeList(count, beginToken, endToken, null)));
  }

  void handleInvalidTopLevelBlock(Token token) {
    popNode(); // block
  }

  @override
  void handleThrowExpression(Token throwToken, Token endToken) {
    Expression expression = popNode();
    pushNode(new Throw(expression, throwToken, endToken));
  }

  @override
  void endAwaitExpression(Token awaitToken, Token endToken) {
    Expression expression = popNode();
    pushNode(new Await(awaitToken, expression));
  }

  @override
  void endRethrowStatement(Token throwToken, Token endToken) {
    pushNode(new Rethrow(throwToken, endToken));
    if (identical(throwToken.stringValue, 'throw')) {
      reporter.reportErrorMessage(reporter.spanFromToken(throwToken),
          MessageKind.MISSING_EXPRESSION_IN_THROW);
    }
  }

  @override
  void handleUnaryPrefixExpression(Token token) {
    pushNode(new Send.prefix(popNode(), new Operator(token)));
  }

  @override
  void handleSuperExpression(Token token, IdentifierContext context) {
    pushNode(new Identifier(token));
  }

  @override
  void handleThisExpression(Token token, IdentifierContext context) {
    pushNode(new Identifier(token));
  }

  void handleUnaryAssignmentExpression(Token token, bool isPrefix) {
    Node node = popNode();
    Send send = node.asSend();
    if (send == null) {
      reportNotAssignable(node);
    }
    if (!(send.isPropertyAccess || send.isIndex)) {
      reportNotAssignable(node);
    }
    if (send.asSendSet() != null) internalError(node: send);
    Node argument = null;
    if (send.isIndex) argument = send.arguments.head;
    Operator op = new Operator(token);

    if (isPrefix) {
      pushNode(new SendSet.prefix(
          send.receiver, send.selector, op, argument, send.isConditional));
    } else {
      pushNode(new SendSet.postfix(
          send.receiver, send.selector, op, argument, send.isConditional));
    }
  }

  @override
  void handleUnaryPostfixAssignmentExpression(Token token) {
    handleUnaryAssignmentExpression(token, false);
  }

  @override
  void handleUnaryPrefixAssignmentExpression(Token token) {
    handleUnaryAssignmentExpression(token, true);
  }

  @override
  void endInitializers(int count, Token beginToken, Token endToken) {
    pushNode(makeNodeList(count, beginToken, null, ','));
  }

  @override
  void handleNoInitializers() {
    pushNode(null);
  }

  @override
  void handleInvalidMember(Token endToken) {
    popNode(); // Discard metadata
    ++invalidMemberCount;
  }

  @override
  void endMember() {
    // TODO(sigmund): consider moving metadata into each declaration
    // element instead.
    Node node = popNode(); // member
    popNode(); // Discard metadata
    pushNode(node);
    super.endMember();
  }

  @override
  void endFields(int count, Token beginToken, Token endToken) {
    NodeList variables = makeNodeList(count, null, endToken, ",");
    TypeAnnotation type = popNode();
    Modifiers modifiers = popNode();
    pushNode(new VariableDefinitions(type, modifiers, variables));
  }

  @override
  void beginMethod(Token externalToken, Token staticToken, Token covariantToken,
      Token varFinalOrConst, Token name) {
    Link<Node> modifiers = const Link<Node>();
    if (varFinalOrConst != null) {
      modifiers = modifiers.prepend(new Identifier(varFinalOrConst));
    }
    if (covariantToken != null) {
      modifiers = modifiers.prepend(new Identifier(covariantToken));
    }
    if (staticToken != null) {
      modifiers = modifiers.prepend(new Identifier(staticToken));
    }
    if (externalToken != null) {
      modifiers = modifiers.prepend(new Identifier(externalToken));
    }
    if (modifiers.isEmpty) {
      pushNode(Modifiers.EMPTY);
    } else {
      pushNode(new Modifiers(new NodeList(null, modifiers, null, ' ')));
    }
  }

  @override
  void endMethod(
      Token getOrSet, Token beginToken, Token beginParam, Token endToken) {
    Statement body = popNode();
    AsyncModifier asyncModifier = popNode();
    NodeList initializers = popNode();
    NodeList formalParameters = popNode();
    NodeList typeVariables = popNode();
    Expression name = popNode();
    TypeAnnotation returnType = popNode();
    Modifiers modifiers = popNode();
    pushNode(new FunctionExpression(name, typeVariables, formalParameters, body,
        returnType, modifiers, initializers, getOrSet, asyncModifier));
  }

  @override
  void handleLiteralMap(
      int count, Token beginToken, Token constKeyword, Token endToken) {
    NodeList entries = makeNodeList(count, beginToken, endToken, ',');
    NodeList typeArguments = popNode();
    pushNode(new LiteralMap(typeArguments, entries, constKeyword));
  }

  @override
  void endLiteralMapEntry(Token colon, Token endToken) {
    Expression value = popNode();
    Expression key = popNode();
    pushNode(new LiteralMapEntry(key, colon, value));
  }

  @override
  void handleLiteralList(
      int count, Token beginToken, Token constKeyword, Token endToken) {
    NodeList elements = makeNodeList(count, beginToken, endToken, ',');
    pushNode(new LiteralList(popNode(), elements, constKeyword));
  }

  @override
  void handleIndexedExpression(
      Token openSquareBracket, Token closeSquareBracket) {
    NodeList arguments =
        makeNodeList(1, openSquareBracket, closeSquareBracket, null);
    Node receiver = popNode();
    Token token = new Token(TokenType.INDEX, openSquareBracket.charOffset);
    Node selector = new Operator(token);
    pushNode(new Send(receiver, selector, arguments));
  }

  @override
  void endNewExpression(Token token) {
    NodeList arguments = popNode();
    Node name = popNode();
    pushNode(new NewExpression(token, new Send(null, name, arguments)));
  }

  @override
  void endConstExpression(Token token) {
    // [token] carries the 'const' information.
    endNewExpression(token);
  }

  @override
  void handleOperator(Token token) {
    pushNode(new Operator(token));
  }

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

  @override
  void handleOperatorName(Token operatorKeyword, Token token) {
    Operator op = new Operator(token);
    pushNode(new Send(new Identifier(operatorKeyword), op, null));
  }

  @override
  void handleInvalidOperatorName(Token operatorKeyword, Token token) {
    Operator op = new Operator(token);
    pushNode(new Send(new Identifier(operatorKeyword), op, null));
  }

  @override
  void handleNamedArgument(Token colon) {
    Expression expression = popNode();
    Identifier name = popNode();
    pushNode(new NamedArgument(name, colon, expression));
  }

  @override
  void endOptionalFormalParameters(
      int count, Token beginToken, Token endToken) {
    pushNode(makeNodeList(count, beginToken, endToken, ','));
  }

  @override
  void handleIdentifier(Token token, IdentifierContext context) {
    if (IdentifierContext.formalParameterDeclaration == context ||
        IdentifierContext.fieldInitializer == context) {
      var typeAnnotation = popNode();
      if (typeAnnotation is FunctionExpression) {
        pushNode(null); // Signal "no type" to endFormalParameter.
        pushNode(new FunctionExpression(
            new Identifier(token),
            typeAnnotation.typeVariables,
            typeAnnotation.parameters,
            null,
            typeAnnotation.returnType,
            typeAnnotation.modifiers,
            null,
            null,
            null));
        return;
      } else {
        pushNode(typeAnnotation);
      }
    } else if (context == IdentifierContext.enumValueDeclaration) {
      popNode();
    }
    pushNode(new Identifier(token));
  }

  @override
  void endFunctionTypedFormalParameter() {
    NodeList formals = popNode();
    TypeAnnotation returnType = popNode();
    NodeList typeVariables = popNode();
    pushNode(new FunctionExpression(null, typeVariables, formals, null,
        returnType, Modifiers.EMPTY, null, null, null));
  }

  @override
  void handleValuedFormalParameter(Token equals, Token token) {
    Expression defaultValue = popNode();
    Expression parameterName = popNode();
    pushNode(new SendSet(null, parameterName, new Operator(equals),
        new NodeList.singleton(defaultValue)));
  }

  @override
  void handleFormalParameterWithoutValue(Token token) {}

  @override
  void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
    Block finallyBlock = null;
    if (finallyKeyword != null) {
      finallyBlock = popNode();
    }
    NodeList catchBlocks = makeNodeList(catchCount, null, null, null);
    Block tryBlock = popNode();
    pushNode(new TryStatement(
        tryBlock, catchBlocks, finallyBlock, tryKeyword, finallyKeyword));
  }

  @override
  void handleCaseMatch(Token caseKeyword, Token colon) {
    pushNode(new CaseMatch(caseKeyword, popNode(), colon));
  }

  @override
  void handleCatchBlock(Token onKeyword, Token catchKeyword, Token comma) {
    Block block = popNode();
    NodeList formals = catchKeyword != null ? popNode() : null;
    TypeAnnotation type = onKeyword != null ? popNode() : null;
    pushNode(new CatchBlock(type, formals, block, onKeyword, catchKeyword));
  }

  @override
  void endSwitchStatement(Token switchKeyword, Token endToken) {
    NodeList cases = popNode();
    ParenthesizedExpression expression = popNode();
    pushNode(new SwitchStatement(expression, cases, switchKeyword));
  }

  @override
  void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
    Link<Node> caseNodes = const Link<Node>();
    while (caseCount > 0) {
      SwitchCase switchCase = popNode();
      caseNodes = caseNodes.prepend(switchCase);
      caseCount--;
    }
    pushNode(new NodeList(beginToken, caseNodes, endToken, null));
  }

  @override
  void endSwitchCase(
      int labelCount,
      int caseCount,
      Token defaultKeyword,
      Token colonAfterDefault,
      int statementCount,
      Token firstToken,
      Token endToken) {
    NodeList statements = makeNodeList(statementCount, null, null, null);
    NodeList labelsAndCases =
        makeNodeList(labelCount + caseCount, null, null, null);
    pushNode(
        new SwitchCase(labelsAndCases, defaultKeyword, statements, firstToken));
  }

  @override
  void handleBreakStatement(
      bool hasTarget, Token breakKeyword, Token endToken) {
    Identifier target = null;
    if (hasTarget) {
      target = popNode();
    }
    pushNode(new BreakStatement(target, breakKeyword, endToken));
  }

  @override
  void handleContinueStatement(
      bool hasTarget, Token continueKeyword, Token endToken) {
    Identifier target = null;
    if (hasTarget) {
      target = popNode();
    }
    pushNode(new ContinueStatement(target, continueKeyword, endToken));
  }

  @override
  void handleEmptyStatement(Token token) {
    pushNode(new EmptyStatement(token));
  }

  @override
  void endFactoryMethod(
      Token beginToken, Token factoryKeyword, Token endToken) {
    super.endFactoryMethod(beginToken, factoryKeyword, endToken);
    Statement body = popNode();
    AsyncModifier asyncModifier = popNode();
    NodeList formals = popNode();
    Node name = popNode();
    Modifiers modifiers = popNode();

    // The parser does not report `factory` as a modifier,
    // but NodeListener considers it to be a modifier.
    // We cannot simply add all tokens from beginToken to factoryToken
    // inclusive because there may be invalid tokens that the parser
    // has skipped and the factoryKeyword may itself be out of order.
    // Because modifiers may be out of order, and some code relies
    // on the order of the nodes in modifiers, we must insert the factory
    // keyword in the correct place by rebuilding the modifiers.
    int modifierCount = 0;
    Identifier factoryNode = new Identifier(factoryKeyword);
    modifiers.nodes.nodes.forEach((Node node) {
      if (factoryNode != null &&
          factoryNode.token.charOffset < node.getBeginToken().charOffset) {
        pushNode(factoryNode);
        ++modifierCount;
        factoryNode = null;
      }
      pushNode(node);
      ++modifierCount;
    });
    if (factoryNode != null) {
      pushNode(factoryNode);
      ++modifierCount;
    }
    handleModifiers(modifierCount);
    modifiers = popNode();

    pushNode(new FunctionExpression(
        name, null, formals, body, null, modifiers, null, null, asyncModifier));
  }

  @override
  void endForIn(Token awaitToken, Token forToken, Token leftParenthesis,
      Token inKeyword, Token endToken) {
    Statement body = popNode();
    Expression expression = popNode();
    Node declaredIdentifier = popNode();
    if (awaitToken == null) {
      pushNode(new SyncForIn(
          declaredIdentifier, expression, body, forToken, inKeyword));
    } else {
      pushNode(new AsyncForIn(declaredIdentifier, expression, body, awaitToken,
          forToken, inKeyword));
    }
  }

  @override
  void endMetadataStar(int count) {
    if (0 == count) {
      pushNode(null);
    } else {
      pushNode(makeNodeList(count, null, null, ' '));
    }
  }

  @override
  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
    NodeList arguments = popNode();
    if (arguments == null) {
      // This is a constant expression.
      Identifier name;
      if (periodBeforeName != null) {
        name = popNode();
      }
      NodeList typeArguments = popNode();
      Node receiver = popNode();
      if (typeArguments != null) {
        receiver = new NominalTypeAnnotation(receiver, typeArguments);
        recoverableError(typeArguments, 'Type arguments are not allowed here.');
      } else {
        Identifier identifier = receiver.asIdentifier();
        Send send = receiver.asSend();
        if (identifier != null) {
          receiver = new Send(null, identifier);
        } else if (send == null) {
          internalError(node: receiver);
        }
      }
      Send send = receiver;
      if (name != null) {
        send = new Send(receiver, name);
      }
      pushNode(new Metadata(beginToken, send));
    } else {
      // This is a const constructor call.
      endConstructorReference(beginToken, periodBeforeName, endToken);
      Node constructor = popNode();
      pushNode(new Metadata(beginToken,
          new NewExpression(null, new Send(null, constructor, arguments))));
    }
  }

  @override
  void endAssert(Token assertKeyword, fasta.Assert kind, Token leftParenthesis,
      Token commaToken, Token semicolonToken) {
    Node message;
    Node condition;
    if (commaToken != null) {
      message = popNode();
    }
    condition = popNode();
    pushNode(new Assert(assertKeyword, condition, message, semicolonToken));
  }

  @override
  void endFunctionExpression(Token beginToken, Token token) {
    Statement body = popNode();
    AsyncModifier asyncModifier = popNode();
    NodeList formals = popNode();
    NodeList typeVariables = popNode();
    pushNode(new FunctionExpression(null, typeVariables, formals, body, null,
        Modifiers.EMPTY, null, null, asyncModifier));
  }

  @override
  void handleIsOperator(Token operator, Token not, Token endToken) {
    TypeAnnotation type = popNode();
    Expression expression = popNode();
    Node argument;
    if (not != null) {
      argument = new Send.prefix(type, new Operator(not));
    } else {
      argument = type;
    }

    NodeList arguments = new NodeList.singleton(argument);
    pushNode(new Send(expression, new Operator(operator), arguments));
  }

  @override
  void handleLabel(Token colon) {
    Identifier name = popNode();
    pushNode(new Label(name, colon));
  }

  @override
  void endLabeledStatement(int labelCount) {
    Statement statement = popNode();
    NodeList labels = makeNodeList(labelCount, null, null, null);
    pushNode(new LabeledStatement(labels, statement));
  }

  @override
  void endTypeVariable(Token token, Token extendsOrSuper) {
    inTypeVariable = false;
    NominalTypeAnnotation bound = popNode();
    Identifier name = popNode();
    // TODO(paulberry): type variable metadata should not be ignored.  See
    // dartbug.com/5841.
    popNode(); // Metadata
    pushNode(new TypeVariable(name, extendsOrSuper, bound));
    rejectBuiltInIdentifier(name);
  }

  @override
  void log(message) {
    reporter.log(message);
  }

  @override
  void handleInvalidFunctionBody(Token token) {
    if (!lastErrorWasNativeFunctionBody) {
      pushNode(null);
    }
    lastErrorWasNativeFunctionBody = false;
  }

  void internalError({Token token, Node node}) {
    // TODO(ahe): This should call reporter.internalError.
    Spannable spannable = (token == null) ? node : token;
    failedAt(spannable, 'Internal error in parser.');
  }
}
