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

import 'package:front_end/src/fasta/fasta_codes.dart' show Message;

import 'package:front_end/src/fasta/fasta_codes.dart' as codes;

import '../common.dart';
import '../diagnostics/messages.dart' show MessageTemplate;
import '../elements/elements.dart'
    show Element, LibraryElement, MetadataAnnotation;
import '../elements/modelx.dart'
    show
        CompilationUnitElementX,
        DeclarationSite,
        ElementX,
        EnumClassElementX,
        FieldElementX,
        LibraryElementX,
        MetadataAnnotationX,
        NamedMixinApplicationElementX,
        VariableList;
import '../id_generator.dart';
import '../native/native.dart' as native;
import '../string_validator.dart' show StringValidator;
import 'package:front_end/src/fasta/scanner.dart'
    show ErrorToken, StringToken, Token;
import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN;
import '../tree/tree.dart';
import '../util/util.dart' show Link, LinkBuilder;
import 'package:front_end/src/fasta/parser.dart'
    show Listener, ParserError, optional;
import 'package:front_end/src/fasta/parser/identifier_context.dart'
    show IdentifierContext;
import 'package:front_end/src/scanner/token.dart' show KeywordToken, TokenType;
import 'partial_elements.dart'
    show
        PartialClassElement,
        PartialElement,
        PartialFieldList,
        PartialFunctionElement,
        PartialMetadataAnnotation,
        PartialTypedefElement;

const bool VERBOSE = false;

/// Options used for scanning.
///
/// Use this to conditionally support special tokens.
///
/// TODO(johnniwinther): This class should be renamed, it is not about options
/// in the same sense as `CompilerOptions` or `DiagnosticOptions`.
class ScannerOptions {
  /// If `true` the pseudo keyword `native` is supported.
  final bool canUseNative;

  const ScannerOptions({this.canUseNative: false});
}

/**
 * A parser event listener designed to work with [PartialParser]. It
 * builds elements representing the top-level declarations found in
 * the parsed compilation unit and records them in
 * [compilationUnitElement].
 */
class ElementListener extends Listener {
  final IdGenerator idGenerator;
  final DiagnosticReporter reporter;
  final ScannerOptions scannerOptions;
  final CompilationUnitElementX compilationUnitElement;
  final StringValidator stringValidator;
  Link<StringQuoting> interpolationScope;

  Link<Node> nodes = const Link<Node>();

  LinkBuilder<MetadataAnnotation> metadata =
      new LinkBuilder<MetadataAnnotation>();

  /// Indicates whether the parser is currently accepting a type variable.
  bool inTypeVariable = false;

  /// Records a stack of booleans for each member parsed (a stack is used to
  /// support nested members which isn't currently possible, but it also serves
  /// as a simple way to tell we're currently parsing a member). In this case,
  /// member refers to members of a library or a class (but currently, classes
  /// themselves are not considered members).  If the top of the stack
  /// (memberErrors.head) is true, the current member has already reported at
  /// least one parse error.
  Link<bool> memberErrors = const Link<bool>();

  bool suppressParseErrors = false;

  /// Set to true each time we parse a native function body. It is reset in
  /// [handleInvalidFunctionBody] which is called immediately after.
  bool lastErrorWasNativeFunctionBody = false;

  LiteralString nativeName;

  ElementListener(this.scannerOptions, DiagnosticReporter reporter,
      this.compilationUnitElement, this.idGenerator)
      : this.reporter = reporter,
        stringValidator = new StringValidator(reporter),
        interpolationScope = const Link<StringQuoting>();

  @override
  Uri get uri => compilationUnitElement?.script?.resourceUri;

  bool get currentMemberHasParseError {
    return !memberErrors.isEmpty && memberErrors.head;
  }

  void pushQuoting(StringQuoting quoting) {
    interpolationScope = interpolationScope.prepend(quoting);
  }

  StringQuoting popQuoting() {
    StringQuoting result = interpolationScope.head;
    interpolationScope = interpolationScope.tail;
    return result;
  }

  StringNode popLiteralString() {
    StringNode node = popNode();
    // TODO(lrn): Handle interpolations in script tags.
    if (node.isInterpolation) {
      reporter.internalError(
          node, "String interpolation not supported in library tags.");
      return null;
    }
    return node;
  }

  bool allowLibraryTags() {
    // Library tags are only allowed in the library file itself, not
    // in sourced files.
    LibraryElement library = compilationUnitElement.implementationLibrary;
    return !compilationUnitElement.hasMembers &&
        library.entryCompilationUnit == compilationUnitElement;
  }

  @override
  void endLibraryName(Token libraryKeyword, Token semicolon) {
    Expression name = popNode();
    addLibraryTag(new LibraryName(
        libraryKeyword, name, popMetadata(compilationUnitElement)));
  }

  @override
  void handleImportPrefix(Token deferredKeyword, Token asKeyword) {
    if (asKeyword == null) {
      // If asKeyword is null, then no prefix has been pushed on the stack.
      // Push a placeholder indicating that there is no prefix.
      pushNode(null);
    }
    pushNode(deferredKeyword != null ? Flag.TRUE : Flag.FALSE);
  }

  @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();
    addLibraryTag(new Import(importKeyword, uri, conditionalUris, prefix,
        combinators, popMetadata(compilationUnitElement),
        isDeferred: isDeferred));
  }

  @override
  void handleRecoverImport(Token semicolon) {
    popNode(); // combinators
    popNode(); // isDeferred
    popNode(); // prefix
    popNode(); // conditionalUris
    // TODO(danrubel): recover
  }

  @override
  void handleDottedName(int count, Token token) {
    NodeList identifiers = makeNodeList(count, null, null, '.');
    pushNode(new DottedName(token, identifiers));
  }

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

  @override
  void endConditionalUri(Token ifToken, Token leftParen, Token equalSign) {
    StringNode uri = popNode();
    LiteralString conditionValue = (equalSign != null) ? popNode() : null;
    DottedName identifier = popNode();
    pushNode(new ConditionalUri(ifToken, identifier, conditionValue, uri));
  }

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

    int id = idGenerator.getNextFreeId();
    Element enclosing = compilationUnitElement;
    pushElement(new EnumClassElementX(
        name.source, enclosing, id, new Enum(enumKeyword, name, names)));
    rejectBuiltInIdentifier(name);
  }

  @override
  void endExport(Token exportKeyword, Token semicolon) {
    NodeList combinators = popNode();
    NodeList conditionalUris = popNode();
    StringNode uri = popNode();
    addLibraryTag(new Export(exportKeyword, uri, conditionalUris, combinators,
        popMetadata(compilationUnitElement)));
  }

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

  @override
  void endHide(Token hideKeyword) => pushCombinator(hideKeyword);

  @override
  void endShow(Token showKeyword) => pushCombinator(showKeyword);

  void pushCombinator(Token keywordToken) {
    NodeList identifiers = popNode();
    pushNode(new Combinator(identifiers, keywordToken));
  }

  @override
  void handleIdentifierList(int count) {
    pushNode(makeNodeList(count, null, null, ","));
  }

  @override
  void endTypeList(int count) {
    pushNode(makeNodeList(count, null, null, ","));
  }

  @override
  void endPart(Token partKeyword, Token semicolon) {
    StringNode uri = popLiteralString();
    addLibraryTag(
        new Part(partKeyword, uri, popMetadata(compilationUnitElement)));
  }

  @override
  void endPartOf(
      Token partKeyword, Token ofKeyword, Token semicolon, bool hasName) {
    Expression name = popNode();
    addPartOfTag(
        new PartOf(partKeyword, name, popMetadata(compilationUnitElement)));
  }

  void addPartOfTag(PartOf tag) {
    compilationUnitElement.setPartOf(tag, reporter);
  }

  @override
  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
    if (periodBeforeName != null) {
      popNode(); // Discard name.
    }
    popNode(); // Discard type parameters
    popNode(); // Discard identifier
    // TODO(paulberry,ahe): type variable metadata should not be ignored.  See
    // dartbug.com/5841.
    if (!inTypeVariable) {
      pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
    }
  }

  @override
  void endTopLevelDeclaration(Token token) {
    if (!metadata.isEmpty) {
      MetadataAnnotationX first = metadata.first;
      recoverableError(reporter.spanFromToken(first.beginToken),
          'Metadata not supported here.');
      metadata.clear();
    }
  }

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

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

  @override
  void handleRecoverClassHeader() {
    popNode(); // superType
  }

  @override
  void endClassDeclaration(Token beginToken, Token endToken) {
    popNode(); // superType
    popNode(); // typeParameters
    Identifier name = popNode();
    int id = idGenerator.getNextFreeId();
    PartialClassElement element = new PartialClassElement(
        name.source, beginToken, endToken, compilationUnitElement, id);
    pushElement(element);
    rejectBuiltInIdentifier(name);
  }

  void rejectBuiltInIdentifier(Identifier name) {
    if (name.token is KeywordToken) {
      TokenType type = name.token.type;
      if (!type.isPseudo) {
        recoverableError(name, "Illegal name '${type.lexeme}'.");
      }
    }
  }

  @override
  void endFunctionTypeAlias(
      Token typedefKeyword, Token equals, Token endToken) {
    Identifier name;
    if (equals == null) {
      popNode(); // TODO(karlklose): do not throw away typeVariables.
      name = popNode();
      popNode(); // returnType
    } else {
      popNode(); // Function type.
      popNode(); // TODO(karlklose): do not throw away typeVariables.
      name = popNode();
    }
    pushElement(new PartialTypedefElement(
        name.source, compilationUnitElement, typedefKeyword, endToken));
    rejectBuiltInIdentifier(name);
  }

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

    int id = idGenerator.getNextFreeId();
    Element enclosing = compilationUnitElement;
    pushElement(new NamedMixinApplicationElementX(
        name.source, enclosing, id, namedMixinApplication));
    rejectBuiltInIdentifier(name);
  }

  @override
  void endMixinApplication(Token withKeyword) {
    NodeList mixins = popNode();
    NominalTypeAnnotation superclass = popNode();
    pushNode(new MixinApplication(superclass, mixins));
  }

  @override
  void handleVoidKeyword(Token token) {
    pushNode(new NominalTypeAnnotation(new Identifier(token), null));
  }

  @override
  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
    bool hasParseError = currentMemberHasParseError;
    memberErrors = memberErrors.tail;
    popNode(); // typeVariables
    Identifier name = popNode();
    popNode(); // type
    Modifiers modifiers = popNode();
    PartialFunctionElement element = new PartialFunctionElement(name.source,
        beginToken, getOrSet, endToken, modifiers, compilationUnitElement);
    element.hasParseError = hasParseError;
    pushElement(element);
  }

  @override
  void endTopLevelFields(int count, Token beginToken, Token endToken) {
    bool hasParseError = currentMemberHasParseError;
    memberErrors = memberErrors.tail;
    void buildFieldElement(Identifier name, VariableList fields) {
      pushElement(new FieldElementX(name, compilationUnitElement, fields));
    }

    NodeList variables = makeNodeList(count, null, null, ",");
    popNode(); // type
    Modifiers modifiers = popNode();
    buildFieldElements(modifiers, variables, compilationUnitElement,
        buildFieldElement, beginToken, endToken, hasParseError);
  }

  @override
  void handleInvalidTopLevelDeclaration(Token endToken) {
    memberErrors = memberErrors.tail;
  }

  void buildFieldElements(
      Modifiers modifiers,
      NodeList variables,
      Element enclosingElement,
      void buildFieldElement(Identifier name, VariableList fields),
      Token beginToken,
      Token endToken,
      bool hasParseError) {
    VariableList fields =
        new PartialFieldList(beginToken, endToken, modifiers, hasParseError);
    for (Link<Node> variableNodes = variables.nodes;
        !variableNodes.isEmpty;
        variableNodes = variableNodes.tail) {
      Expression initializedIdentifier = variableNodes.head;
      Identifier identifier = initializedIdentifier.asIdentifier();
      if (identifier == null) {
        identifier = initializedIdentifier.asSendSet().selector.asIdentifier();
      }
      buildFieldElement(identifier, fields);
    }
  }

  @override
  void handleIdentifier(Token token, IdentifierContext context) {
    if (context == IdentifierContext.enumValueDeclaration) {
      metadata.clear();
    }
    pushNode(new Identifier(token));
  }

  @override
  void handleQualified(Token period) {
    Identifier last = popNode();
    Expression first = popNode();
    pushNode(new Send(first, last));
  }

  @override
  void handleNoConstructorReferenceContinuationAfterTypeArguments(
      Token token) {}

  @override
  void handleNoType(Token lastConsumed) {
    pushNode(null);
  }

  @override
  void beginTypeVariable(Token token) {
    inTypeVariable = true;
  }

  @override
  void endTypeVariable(Token token, Token extendsOrSuper) {
    inTypeVariable = false;
    NominalTypeAnnotation bound = popNode();
    Identifier name = popNode();
    pushNode(new TypeVariable(name, extendsOrSuper, bound));
    rejectBuiltInIdentifier(name);
  }

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

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

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

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

  @override
  void handleType(Token beginToken, Token endToken) {
    NodeList typeArguments = popNode();
    Expression typeName = popNode();
    pushNode(new NominalTypeAnnotation(typeName, typeArguments));
  }

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

  @override
  void endFunctionType(Token functionToken, Token endToken) {
    popNode(); // Return type.
    popNode(); // Type parameters.
    pushNode(null);
  }

  @override
  void handleParenthesizedExpression(Token token) {
    Expression expression = popNode();
    pushNode(new ParenthesizedExpression(expression, token));
  }

  @override
  void handleModifier(Token token) {
    pushNode(new Identifier(token));
  }

  @override
  void handleModifiers(int count) {
    if (count == 0) {
      pushNode(Modifiers.EMPTY);
    } else {
      NodeList modifierNodes = makeNodeList(count, null, null, ' ');
      pushNode(new Modifiers(modifierNodes));
    }
  }

  @override
  Token handleUnrecoverableError(Token token, Message message) {
    Token next = handleError(token, message);
    if (next == null &&
        message.code != codes.codeUnterminatedComment &&
        message.code != codes.codeUnterminatedString) {
      throw new ParserError.fromTokens(token, token, message);
    } else {
      return next;
    }
  }

  @override
  void handleRecoverableError(
      Message message, Token startToken, Token endToken) {
    if (message == codes.messageNativeClauseShouldBeAnnotation) {
      native.checkAllowedLibrary(this, startToken);
      return;
    }
    handleError(startToken, message);
  }

  @override
  void handleInvalidExpression(Token token) {
    pushNode(new ErrorExpression(token));
  }

  @override
  void handleInvalidFunctionBody(Token token) {
    lastErrorWasNativeFunctionBody = false;
  }

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

  Token handleError(Token token, Message message) {
    MessageKind errorCode;
    Map<String, dynamic> arguments = message.arguments;

    switch (message.code.dart2jsCode) {
      case "MISSING_TOKEN_BEFORE_THIS":
        String expected = arguments["string"];
        // TODO(danrubel): This functionality is being replaced by
        // the parser's ensureSemicolon method.
        if (identical(";", expected)) {
          // When a semicolon is missing, it often leads to an error on the
          // following line. So we try to find the token preceding the semicolon
          // and report that something is missing *after* it.
          Token preceding = findPrecedingToken(token);
          if (preceding == token) {
            reportErrorFromToken(token, MessageKind.MISSING_TOKEN_BEFORE_THIS,
                {'token': expected});
          } else {
            reportErrorFromToken(preceding,
                MessageKind.MISSING_TOKEN_AFTER_THIS, {'token': expected});
          }
          return preceding;
        } else {
          reportFatalError(
              reporter.spanFromToken(token),
              MessageTemplate.TEMPLATES[MessageKind.MISSING_TOKEN_BEFORE_THIS]
                  .message({'token': expected}, true).toString());
          return null;
        }
        break;

      case "EXPECTED_IDENTIFIER":
        if (token is KeywordToken) {
          reportErrorFromToken(
              token,
              MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
              {'keyword': token.lexeme});
        } else if (token is ErrorToken) {
          // TODO(ahe): This is dead code.
          return newSyntheticToken(synthesizeIdentifier(token));
        } else {
          reportFatalError(reporter.spanFromToken(token),
              "Expected identifier, but got '${token.lexeme}'.");
        }
        return newSyntheticToken(token);

      case "NATIVE_OR_BODY_EXPECTED":
        if (optional("native", token)) {
          return newSyntheticToken(native.handleNativeBlockToSkip(this, token));
        } else {
          errorCode = MessageKind.BODY_EXPECTED;
        }
        break;

      case "NATIVE_OR_FATAL":
        if (optional("native", token)) {
          lastErrorWasNativeFunctionBody = true;
          return newSyntheticToken(
              native.handleNativeFunctionBody(this, token));
        } else {
          reportFatalError(reporter.spanFromToken(token), message.message);
        }
        return null;

      case "UNMATCHED_TOKEN":
        reportErrorFromToken(token, MessageKind.UNMATCHED_TOKEN,
            {"end": arguments["string"], "begin": arguments["token"]});
        Token next = token;
        while (next.next is ErrorToken) {
          next = next.next;
        }
        return next;

      case "EMPTY_NAMED_PARAMETER_LIST":
        errorCode = MessageKind.EMPTY_NAMED_PARAMETER_LIST;
        break;

      case "EMPTY_OPTIONAL_PARAMETER_LIST":
        errorCode = MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST;
        break;

      case "BODY_EXPECTED":
        errorCode = MessageKind.BODY_EXPECTED;
        break;

      case "HEX_DIGIT_EXPECTED":
        errorCode = MessageKind.HEX_DIGIT_EXPECTED;
        break;

      case "GENERIC":
        errorCode = MessageKind.GENERIC;
        arguments = {"text": message.message};
        break;

      case "EXTRANEOUS_MODIFIER":
        errorCode = MessageKind.EXTRANEOUS_MODIFIER;
        arguments = {"modifier": arguments["token"]};
        break;

      case "EXTRANEOUS_MODIFIER_REPLACE":
        errorCode = MessageKind.EXTRANEOUS_MODIFIER_REPLACE;
        arguments = {"modifier": arguments["token"]};
        break;

      case "INVALID_AWAIT_FOR":
        errorCode = MessageKind.INVALID_AWAIT_FOR;
        break;

      case "BAD_INPUT_CHARACTER":
        errorCode = MessageKind.BAD_INPUT_CHARACTER;
        int codePoint = arguments["codePoint"];
        String hex = codePoint.toRadixString(16);
        String padding = "0000".substring(hex.length);
        arguments = {'characterHex': padding};
        break;

      case "INVALID_INLINE_FUNCTION_TYPE":
        errorCode = MessageKind.INVALID_INLINE_FUNCTION_TYPE;
        break;

      case "INVALID_SYNC_MODIFIER":
        errorCode = MessageKind.INVALID_SYNC_MODIFIER;
        break;

      case "VOID_NOT_ALLOWED":
        errorCode = MessageKind.VOID_NOT_ALLOWED;
        break;

      case "MALFORMED_STRING_LITERAL":
        errorCode = MessageKind.MALFORMED_STRING_LITERAL;
        break;

      case "EXPONENT_MISSING":
        errorCode = MessageKind.EXPONENT_MISSING;
        break;

      case "POSITIONAL_PARAMETER_WITH_EQUALS":
        errorCode = MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS;
        break;

      case "REQUIRED_PARAMETER_WITH_DEFAULT":
        errorCode = MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT;
        break;

      case "UNMATCHED_TOKEN":
        errorCode = MessageKind.UNMATCHED_TOKEN;
        break;

      case "UNSUPPORTED_PREFIX_PLUS":
        errorCode = MessageKind.UNSUPPORTED_PREFIX_PLUS;
        break;

      case "UNTERMINATED_COMMENT":
        errorCode = MessageKind.UNTERMINATED_COMMENT;
        break;

      case "UNTERMINATED_STRING":
        errorCode = MessageKind.UNTERMINATED_STRING;
        arguments = {"quote": arguments["string"]};
        break;

      case "UNTERMINATED_TOKEN":
        errorCode = MessageKind.UNTERMINATED_TOKEN;
        break;

      case "*fatal*":
        // This is an error that Fasta can recover from, but dart2js can't.
        reportFatalError(reporter.spanFromToken(token), message.message);
        return null;

      case "*ignored*":
        // This is an error that Fasta reports as a recoverable error during
        // parsing. For historical reasons, dart2js implements this in a later
        // phase already, so we just ignore it. Another possibilty is that we
        // wan't to avoid introducing a breaking change to dart2js.
        return null;

      default:
        throw "Unexpected message code: ${message.code}";
    }
    SourceSpan span = reporter.spanFromToken(token);
    reportError(span, errorCode, arguments);
    return null;
  }

  /// Finds the preceding token via the begin token of the last AST node pushed
  /// on the [nodes] stack.
  Token findPrecedingToken(Token token) {
    Token result;
    Link<Node> nodes = this.nodes;
    while (!nodes.isEmpty) {
      result = findPrecedingTokenFromNode(nodes.head, token);
      if (result != null) {
        return result;
      }
      nodes = nodes.tail;
    }
    if (compilationUnitElement != null) {
      if (compilationUnitElement is CompilationUnitElementX) {
        CompilationUnitElementX unit = compilationUnitElement;
        Link<Element> members = unit.localMembers;
        while (!members.isEmpty) {
          ElementX member = members.head;
          DeclarationSite site = member.declarationSite;
          if (site is PartialElement) {
            result = findPrecedingTokenFromToken(site.endToken, token);
            if (result != null) {
              return result;
            }
          }
          members = members.tail;
        }
        result =
            findPrecedingTokenFromNode(compilationUnitElement.partTag, token);
        if (result != null) {
          return result;
        }
      }
    }
    return token;
  }

  Token findPrecedingTokenFromNode(Node node, Token token) {
    if (node != null) {
      return findPrecedingTokenFromToken(node.getBeginToken(), token);
    }
    return null;
  }

  Token findPrecedingTokenFromToken(Token start, Token token) {
    if (start != null) {
      Token current = start;
      while (current.kind != Tokens.EOF_TOKEN && current.next != token) {
        current = current.next;
      }
      if (current.kind != Tokens.EOF_TOKEN) {
        return current;
      }
    }
    return null;
  }

  /// Finds the preceding token via the begin token of the last AST node pushed
  /// on the [nodes] stack.
  Token synthesizeIdentifier(Token token) {
    Token synthesizedToken =
        new StringToken.fromString(TokenType.IDENTIFIER, '?', token.charOffset);
    synthesizedToken.next = token.next;
    return synthesizedToken;
  }

  void recoverableError(Spannable node, String message) {
    // TODO(johnniwinther): Make recoverable errors non-fatal.
    reportFatalError(node, message);
  }

  void pushElement(ElementX element) {
    assert(element.declarationSite != null,
        failedAt(element, 'Missing declaration site for $element.'));
    popMetadata(element);
    compilationUnitElement.addMember(element, reporter);
  }

  List<MetadataAnnotation> popMetadata(ElementX element) {
    List<MetadataAnnotation> result = metadata.toList();
    element.metadata = result;
    metadata.clear();
    return result;
  }

  void pushMetadata(MetadataAnnotation annotation) {
    metadata.addLast(annotation);
  }

  void addLibraryTag(LibraryTag tag) {
    if (!allowLibraryTags()) {
      recoverableError(tag, 'Library tags not allowed here.');
    }
    LibraryElementX implementationLibrary =
        compilationUnitElement.implementationLibrary;
    implementationLibrary.addTag(tag, reporter);
  }

  void pushNode(Node node) {
    nodes = nodes.prepend(node);
    if (VERBOSE) log("push $nodes");
  }

  Node popNode() {
    assert(!nodes.isEmpty);
    Node node = nodes.head;
    nodes = nodes.tail;
    if (VERBOSE) log("pop $nodes");
    return node;
  }

  void log(message) {
    print(message);
  }

  NodeList makeNodeList(
      int count, Token beginToken, Token endToken, String delimiter) {
    Link<Node> poppedNodes = const Link<Node>();
    for (; count > 0; --count) {
      // This effectively reverses the order of nodes so they end up
      // in correct (source) order.
      poppedNodes = poppedNodes.prepend(popNode());
    }
    return new NodeList(beginToken, poppedNodes, endToken, delimiter);
  }

  @override
  void beginLiteralString(Token token) {
    String source = token.lexeme;
    StringQuoting quoting = StringValidator.quotingFromString(source);
    pushQuoting(quoting);
    // Just wrap the token for now. At the end of the interpolation,
    // when we know how many there are, go back and validate the tokens.
    pushNode(new LiteralString(token, null));
  }

  @override
  void handleStringPart(Token token) {
    // Just push an unvalidated token now, and replace it when we know the
    // end of the interpolation.
    pushNode(new LiteralString(token, null));
  }

  @override
  void endLiteralString(int interpolationCount, Token endToken) {
    StringQuoting quoting = popQuoting();

    Link<StringInterpolationPart> parts = const Link<StringInterpolationPart>();
    // Parts of the string interpolation are popped in reverse order,
    // starting with the last literal string part.
    bool isLast = true;
    for (int i = 0; i < interpolationCount; i++) {
      LiteralString string = popNode();
      DartString validation = stringValidator.validateInterpolationPart(
          string.token, quoting,
          isFirst: false, isLast: isLast);
      // Replace the unvalidated LiteralString with a new LiteralString
      // object that has the validation result included.
      string = new LiteralString(string.token, validation);
      Expression expression = popNode();
      parts = parts.prepend(new StringInterpolationPart(expression, string));
      isLast = false;
    }

    LiteralString string = popNode();
    DartString validation = stringValidator.validateInterpolationPart(
        string.token, quoting,
        isFirst: true, isLast: isLast);
    string = new LiteralString(string.token, validation);
    if (isLast) {
      pushNode(string);
    } else {
      NodeList partNodes = new NodeList(null, parts, null, "");
      pushNode(new StringInterpolation(string, partNodes));
    }
  }

  @override
  void handleNativeClause(Token nativeToken, bool hasName) {
    if (hasName) {
      nativeName = popNode(); // LiteralString
    } else {
      nativeName = null;
    }
  }

  @override
  void handleStringJuxtaposition(int stringCount) {
    assert(stringCount != 0);
    Expression accumulator = popNode();
    stringCount--;
    while (stringCount > 0) {
      Expression expression = popNode();
      accumulator = new StringJuxtaposition(expression, accumulator);
      stringCount--;
    }
    pushNode(accumulator);
  }

  @override
  void beginMember() {
    memberErrors = memberErrors.prepend(false);
  }

  @override
  void beginTopLevelMember(Token token) {
    beginMember();
  }

  @override
  void endMember() {
    memberErrors = memberErrors.tail;
  }

  /// Don't call this method. Should only be used as a last resort when there
  /// is no feasible way to recover from a parser error.
  void reportFatalError(Spannable spannable, String message) {
    reportError(spannable, MessageKind.GENERIC, {'text': message});
    // Some parse errors are infeasible to recover from, so we throw an error.
    SourceSpan span = reporter.spanFromSpannable(spannable);
    throw new ParserError(
        span.begin, span.end, codes.templateUnspecified.withArguments(message));
  }

  void reportError(Spannable spannable, MessageKind errorCode,
      [Map arguments = const {}]) {
    if (currentMemberHasParseError) return; // Error already reported.
    if (suppressParseErrors) return;
    if (!memberErrors.isEmpty) {
      memberErrors = memberErrors.tail.prepend(true);
    }
    reporter.reportErrorMessage(spannable, errorCode, arguments);
  }

  void reportErrorFromToken(Token token, MessageKind errorCode,
      [Map arguments = const {}]) {
    reportError(reporter.spanFromToken(token), errorCode, arguments);
  }
}
