// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_PARSING_PREPARSER_H
#define V8_PARSING_PREPARSER_H

#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/parsing/parser-base.h"
#include "src/parsing/preparse-data.h"
#include "src/pending-compilation-error-handler.h"

namespace v8 {
namespace internal {

// Whereas the Parser generates AST during the recursive descent,
// the PreParser doesn't create a tree. Instead, it passes around minimal
// data objects (PreParserExpression, PreParserIdentifier etc.) which contain
// just enough data for the upper layer functions. PreParserFactory is
// responsible for creating these dummy objects. It provides a similar kind of
// interface as AstNodeFactory, so ParserBase doesn't need to care which one is
// used.

class ProducedPreParsedScopeData;

class PreParserIdentifier {
 public:
  PreParserIdentifier() : type_(kUnknownIdentifier) {}
  static PreParserIdentifier Default() {
    return PreParserIdentifier(kUnknownIdentifier);
  }
  static PreParserIdentifier Empty() {
    return PreParserIdentifier(kEmptyIdentifier);
  }
  static PreParserIdentifier Eval() {
    return PreParserIdentifier(kEvalIdentifier);
  }
  static PreParserIdentifier Arguments() {
    return PreParserIdentifier(kArgumentsIdentifier);
  }
  static PreParserIdentifier Undefined() {
    return PreParserIdentifier(kUndefinedIdentifier);
  }
  static PreParserIdentifier FutureReserved() {
    return PreParserIdentifier(kFutureReservedIdentifier);
  }
  static PreParserIdentifier FutureStrictReserved() {
    return PreParserIdentifier(kFutureStrictReservedIdentifier);
  }
  static PreParserIdentifier Let() {
    return PreParserIdentifier(kLetIdentifier);
  }
  static PreParserIdentifier Static() {
    return PreParserIdentifier(kStaticIdentifier);
  }
  static PreParserIdentifier Yield() {
    return PreParserIdentifier(kYieldIdentifier);
  }
  static PreParserIdentifier Prototype() {
    return PreParserIdentifier(kPrototypeIdentifier);
  }
  static PreParserIdentifier Constructor() {
    return PreParserIdentifier(kConstructorIdentifier);
  }
  static PreParserIdentifier Enum() {
    return PreParserIdentifier(kEnumIdentifier);
  }
  static PreParserIdentifier Await() {
    return PreParserIdentifier(kAwaitIdentifier);
  }
  static PreParserIdentifier Async() {
    return PreParserIdentifier(kAsyncIdentifier);
  }
  static PreParserIdentifier Name() {
    return PreParserIdentifier(kNameIdentifier);
  }
  bool IsEmpty() const { return type_ == kEmptyIdentifier; }
  bool IsEval() const { return type_ == kEvalIdentifier; }
  bool IsArguments() const { return type_ == kArgumentsIdentifier; }
  bool IsEvalOrArguments() const { return IsEval() || IsArguments(); }
  bool IsUndefined() const { return type_ == kUndefinedIdentifier; }
  bool IsLet() const { return type_ == kLetIdentifier; }
  bool IsStatic() const { return type_ == kStaticIdentifier; }
  bool IsYield() const { return type_ == kYieldIdentifier; }
  bool IsPrototype() const { return type_ == kPrototypeIdentifier; }
  bool IsConstructor() const { return type_ == kConstructorIdentifier; }
  bool IsEnum() const { return type_ == kEnumIdentifier; }
  bool IsAwait() const { return type_ == kAwaitIdentifier; }
  bool IsName() const { return type_ == kNameIdentifier; }

  // Allow identifier->name()[->length()] to work. The preparser
  // does not need the actual positions/lengths of the identifiers.
  const PreParserIdentifier* operator->() const { return this; }
  const PreParserIdentifier raw_name() const { return *this; }

  int position() const { return 0; }
  int length() const { return 0; }

 private:
  enum Type {
    kEmptyIdentifier,
    kUnknownIdentifier,
    kFutureReservedIdentifier,
    kFutureStrictReservedIdentifier,
    kLetIdentifier,
    kStaticIdentifier,
    kYieldIdentifier,
    kEvalIdentifier,
    kArgumentsIdentifier,
    kUndefinedIdentifier,
    kPrototypeIdentifier,
    kConstructorIdentifier,
    kEnumIdentifier,
    kAwaitIdentifier,
    kAsyncIdentifier,
    kNameIdentifier
  };

  explicit PreParserIdentifier(Type type) : type_(type), string_(nullptr) {}
  Type type_;
  // Only non-nullptr when PreParser.track_unresolved_variables_ is true.
  const AstRawString* string_;
  friend class PreParserExpression;
  friend class PreParser;
  friend class PreParserFactory;
};


class PreParserExpression {
 public:
  PreParserExpression()
      : code_(TypeField::encode(kEmpty)), variables_(nullptr) {}

  static PreParserExpression Empty() { return PreParserExpression(); }

  static PreParserExpression Default(
      ZoneList<VariableProxy*>* variables = nullptr) {
    return PreParserExpression(TypeField::encode(kExpression), variables);
  }

  static PreParserExpression Spread(PreParserExpression expression) {
    return PreParserExpression(TypeField::encode(kSpreadExpression),
                               expression.variables_);
  }

  static PreParserExpression FromIdentifier(PreParserIdentifier id,
                                            VariableProxy* variable,
                                            Zone* zone) {
    PreParserExpression expression(TypeField::encode(kIdentifierExpression) |
                                   IdentifierTypeField::encode(id.type_));
    expression.AddVariable(variable, zone);
    return expression;
  }

  static PreParserExpression BinaryOperation(PreParserExpression left,
                                             Token::Value op,
                                             PreParserExpression right,
                                             Zone* zone) {
    if (op == Token::COMMA) {
      // Possibly an arrow function parameter list.
      if (left.variables_ == nullptr) {
        return PreParserExpression(TypeField::encode(kExpression),
                                   right.variables_);
      }
      if (right.variables_ != nullptr) {
        for (auto variable : *right.variables_) {
          left.variables_->Add(variable, zone);
        }
      }
      return PreParserExpression(TypeField::encode(kExpression),
                                 left.variables_);
    }
    return PreParserExpression(TypeField::encode(kExpression));
  }

  static PreParserExpression Assignment(ZoneList<VariableProxy*>* variables) {
    return PreParserExpression(TypeField::encode(kExpression) |
                                   ExpressionTypeField::encode(kAssignment),
                               variables);
  }

  static PreParserExpression NewTargetExpression() {
    return PreParserExpression(TypeField::encode(kExpression) |
                               ExpressionTypeField::encode(kNewTarget));
  }

  static PreParserExpression ObjectLiteral(
      ZoneList<VariableProxy*>* variables) {
    return PreParserExpression(TypeField::encode(kObjectLiteralExpression),
                               variables);
  }

  static PreParserExpression ArrayLiteral(ZoneList<VariableProxy*>* variables) {
    return PreParserExpression(TypeField::encode(kArrayLiteralExpression),
                               variables);
  }

  static PreParserExpression StringLiteral() {
    return PreParserExpression(TypeField::encode(kStringLiteralExpression));
  }

  static PreParserExpression UseStrictStringLiteral() {
    return PreParserExpression(TypeField::encode(kStringLiteralExpression) |
                               IsUseStrictField::encode(true));
  }

  static PreParserExpression UseAsmStringLiteral() {
    return PreParserExpression(TypeField::encode(kStringLiteralExpression) |
                               IsUseAsmField::encode(true));
  }

  static PreParserExpression This(ZoneList<VariableProxy*>* variables) {
    return PreParserExpression(TypeField::encode(kExpression) |
                                   ExpressionTypeField::encode(kThisExpression),
                               variables);
  }

  static PreParserExpression ThisProperty() {
    return PreParserExpression(
        TypeField::encode(kExpression) |
        ExpressionTypeField::encode(kThisPropertyExpression));
  }

  static PreParserExpression Property() {
    return PreParserExpression(
        TypeField::encode(kExpression) |
        ExpressionTypeField::encode(kPropertyExpression));
  }

  static PreParserExpression Call() {
    return PreParserExpression(TypeField::encode(kExpression) |
                               ExpressionTypeField::encode(kCallExpression));
  }

  static PreParserExpression CallEval() {
    return PreParserExpression(
        TypeField::encode(kExpression) |
        ExpressionTypeField::encode(kCallEvalExpression));
  }

  static PreParserExpression SuperCallReference() {
    return PreParserExpression(
        TypeField::encode(kExpression) |
        ExpressionTypeField::encode(kSuperCallReference));
  }

  static PreParserExpression NoTemplateTag() {
    return PreParserExpression(
        TypeField::encode(kExpression) |
        ExpressionTypeField::encode(kNoTemplateTagExpression));
  }

  bool IsEmpty() const { return TypeField::decode(code_) == kEmpty; }

  bool IsIdentifier() const {
    return TypeField::decode(code_) == kIdentifierExpression;
  }

  PreParserIdentifier AsIdentifier() const {
    DCHECK(IsIdentifier());
    return PreParserIdentifier(IdentifierTypeField::decode(code_));
  }

  bool IsAssignment() const {
    return TypeField::decode(code_) == kExpression &&
           ExpressionTypeField::decode(code_) == kAssignment;
  }

  bool IsObjectLiteral() const {
    return TypeField::decode(code_) == kObjectLiteralExpression;
  }

  bool IsArrayLiteral() const {
    return TypeField::decode(code_) == kArrayLiteralExpression;
  }

  bool IsStringLiteral() const {
    return TypeField::decode(code_) == kStringLiteralExpression;
  }

  bool IsUseStrictLiteral() const {
    return TypeField::decode(code_) == kStringLiteralExpression &&
           IsUseStrictField::decode(code_);
  }

  bool IsUseAsmLiteral() const {
    return TypeField::decode(code_) == kStringLiteralExpression &&
           IsUseAsmField::decode(code_);
  }

  bool IsThis() const {
    return TypeField::decode(code_) == kExpression &&
           ExpressionTypeField::decode(code_) == kThisExpression;
  }

  bool IsThisProperty() const {
    return TypeField::decode(code_) == kExpression &&
           ExpressionTypeField::decode(code_) == kThisPropertyExpression;
  }

  bool IsProperty() const {
    return TypeField::decode(code_) == kExpression &&
           (ExpressionTypeField::decode(code_) == kPropertyExpression ||
            ExpressionTypeField::decode(code_) == kThisPropertyExpression);
  }

  bool IsCall() const {
    return TypeField::decode(code_) == kExpression &&
           (ExpressionTypeField::decode(code_) == kCallExpression ||
            ExpressionTypeField::decode(code_) == kCallEvalExpression);
  }

  bool IsSuperCallReference() const {
    return TypeField::decode(code_) == kExpression &&
           ExpressionTypeField::decode(code_) == kSuperCallReference;
  }

  bool IsValidReferenceExpression() const {
    return IsIdentifier() || IsProperty();
  }

  // At the moment PreParser doesn't track these expression types.
  bool IsFunctionLiteral() const { return false; }
  bool IsCallNew() const { return false; }

  bool IsNoTemplateTag() const {
    return TypeField::decode(code_) == kExpression &&
           ExpressionTypeField::decode(code_) == kNoTemplateTagExpression;
  }

  bool IsSpread() const {
    return TypeField::decode(code_) == kSpreadExpression;
  }

  PreParserExpression AsFunctionLiteral() { return *this; }

  // Dummy implementation for making expression->somefunc() work in both Parser
  // and PreParser.
  PreParserExpression* operator->() { return this; }

  // More dummy implementations of things PreParser doesn't need to track:
  void SetShouldEagerCompile() {}
  void set_should_be_used_once_hint() {}

  int position() const { return kNoSourcePosition; }
  void set_function_token_position(int position) {}

 private:
  enum Type {
    kEmpty,
    kExpression,
    kIdentifierExpression,
    kStringLiteralExpression,
    kSpreadExpression,
    kObjectLiteralExpression,
    kArrayLiteralExpression
  };

  enum ExpressionType {
    kThisExpression,
    kThisPropertyExpression,
    kPropertyExpression,
    kCallExpression,
    kCallEvalExpression,
    kSuperCallReference,
    kNoTemplateTagExpression,
    kAssignment,
    kNewTarget
  };

  explicit PreParserExpression(uint32_t expression_code,
                               ZoneList<VariableProxy*>* variables = nullptr)
      : code_(expression_code), variables_(variables) {}

  void AddVariable(VariableProxy* variable, Zone* zone) {
    if (variable == nullptr) {
      return;
    }
    if (variables_ == nullptr) {
      variables_ = new (zone) ZoneList<VariableProxy*>(1, zone);
    }
    variables_->Add(variable, zone);
  }

  // The first three bits are for the Type.
  typedef BitField<Type, 0, 3> TypeField;

  // The high order bit applies only to nodes which would inherit from the
  // Expression ASTNode --- This is by necessity, due to the fact that
  // Expression nodes may be represented as multiple Types, not exclusively
  // through kExpression.
  // TODO(caitp, adamk): clean up PreParserExpression bitfields.
  typedef BitField<bool, 31, 1> ParenthesizedField;

  // The rest of the bits are interpreted depending on the value
  // of the Type field, so they can share the storage.
  typedef BitField<ExpressionType, TypeField::kNext, 4> ExpressionTypeField;
  typedef BitField<bool, TypeField::kNext, 1> IsUseStrictField;
  typedef BitField<bool, IsUseStrictField::kNext, 1> IsUseAsmField;
  typedef BitField<PreParserIdentifier::Type, TypeField::kNext, 10>
      IdentifierTypeField;
  typedef BitField<bool, TypeField::kNext, 1> HasCoverInitializedNameField;

  uint32_t code_;
  // If the PreParser is used in the variable tracking mode, PreParserExpression
  // accumulates variables in that expression.
  ZoneList<VariableProxy*>* variables_;

  friend class PreParser;
  friend class PreParserFactory;
  template <typename T>
  friend class PreParserList;
};


// The pre-parser doesn't need to build lists of expressions, identifiers, or
// the like. If the PreParser is used in variable tracking mode, it needs to
// build lists of variables though.
template <typename T>
class PreParserList {
 public:
  // These functions make list->Add(some_expression) work (and do nothing).
  PreParserList() : length_(0), variables_(nullptr) {}
  PreParserList* operator->() { return this; }
  void Add(const T& element, Zone* zone);
  int length() const { return length_; }
  static PreParserList Null() { return PreParserList(-1); }
  bool IsNull() const { return length_ == -1; }
  void Set(int index, const T& element) {}

 private:
  explicit PreParserList(int n) : length_(n), variables_(nullptr) {}
  int length_;
  ZoneList<VariableProxy*>* variables_;

  friend class PreParser;
  friend class PreParserFactory;
};

template <>
inline void PreParserList<PreParserExpression>::Add(
    const PreParserExpression& expression, Zone* zone) {
  if (expression.variables_ != nullptr) {
    DCHECK(FLAG_lazy_inner_functions);
    DCHECK(zone != nullptr);
    if (variables_ == nullptr) {
      variables_ = new (zone) ZoneList<VariableProxy*>(1, zone);
    }
    for (auto identifier : (*expression.variables_)) {
      variables_->Add(identifier, zone);
    }
  }
  ++length_;
}

template <typename T>
void PreParserList<T>::Add(const T& element, Zone* zone) {
  ++length_;
}

typedef PreParserList<PreParserExpression> PreParserExpressionList;

class PreParserStatement;
typedef PreParserList<PreParserStatement> PreParserStatementList;

class PreParserStatement {
 public:
  static PreParserStatement Default() {
    return PreParserStatement(kUnknownStatement);
  }

  static PreParserStatement Null() {
    return PreParserStatement(kNullStatement);
  }

  static PreParserStatement Empty() {
    return PreParserStatement(kEmptyStatement);
  }

  static PreParserStatement Jump() {
    return PreParserStatement(kJumpStatement);
  }

  // Creates expression statement from expression.
  // Preserves being an unparenthesized string literal, possibly
  // "use strict".
  static PreParserStatement ExpressionStatement(
      PreParserExpression expression) {
    if (expression.IsUseStrictLiteral()) {
      return PreParserStatement(kUseStrictExpressionStatement);
    }
    if (expression.IsUseAsmLiteral()) {
      return PreParserStatement(kUseAsmExpressionStatement);
    }
    if (expression.IsStringLiteral()) {
      return PreParserStatement(kStringLiteralExpressionStatement);
    }
    return Default();
  }

  bool IsStringLiteral() {
    return code_ == kStringLiteralExpressionStatement || IsUseStrictLiteral() ||
           IsUseAsmLiteral();
  }

  bool IsUseStrictLiteral() {
    return code_ == kUseStrictExpressionStatement;
  }

  bool IsUseAsmLiteral() { return code_ == kUseAsmExpressionStatement; }

  bool IsJumpStatement() {
    return code_ == kJumpStatement;
  }

  bool IsNullStatement() { return code_ == kNullStatement; }

  bool IsEmptyStatement() { return code_ == kEmptyStatement; }

  // Dummy implementation for making statement->somefunc() work in both Parser
  // and PreParser.
  PreParserStatement* operator->() { return this; }

  PreParserStatementList statements() { return PreParserStatementList(); }
  void set_scope(Scope* scope) {}
  void Initialize(PreParserExpression cond, PreParserStatement body,
                  const SourceRange& body_range = {}) {}
  void Initialize(PreParserStatement init, PreParserExpression cond,
                  PreParserStatement next, PreParserStatement body,
                  const SourceRange& body_range = {}) {}

 private:
  enum Type {
    kNullStatement,
    kEmptyStatement,
    kUnknownStatement,
    kJumpStatement,
    kStringLiteralExpressionStatement,
    kUseStrictExpressionStatement,
    kUseAsmExpressionStatement,
  };

  explicit PreParserStatement(Type code) : code_(code) {}
  Type code_;
};


class PreParserFactory {
 public:
  explicit PreParserFactory(AstValueFactory* ast_value_factory, Zone* zone)
      : ast_node_factory_(ast_value_factory, zone), zone_(zone) {}

  void set_zone(Zone* zone) {
    ast_node_factory_.set_zone(zone);
    zone_ = zone;
  }

  AstNodeFactory* ast_node_factory() { return &ast_node_factory_; }

  PreParserExpression NewStringLiteral(PreParserIdentifier identifier,
                                       int pos) {
    // This is needed for object literal property names. Property names are
    // normalized to string literals during object literal parsing.
    PreParserExpression expression = PreParserExpression::Default();
    if (identifier.string_ != nullptr) {
      DCHECK(FLAG_lazy_inner_functions);
      VariableProxy* variable = ast_node_factory_.NewVariableProxy(
          identifier.string_, NORMAL_VARIABLE);
      expression.AddVariable(variable, zone_);
    }
    return expression;
  }
  PreParserExpression NewNumberLiteral(double number,
                                       int pos) {
    return PreParserExpression::Default();
  }
  PreParserExpression NewUndefinedLiteral(int pos) {
    return PreParserExpression::Default();
  }
  PreParserExpression NewRegExpLiteral(PreParserIdentifier js_pattern,
                                       int js_flags, int pos) {
    return PreParserExpression::Default();
  }
  PreParserExpression NewArrayLiteral(PreParserExpressionList values,
                                      int first_spread_index, int pos) {
    return PreParserExpression::ArrayLiteral(values.variables_);
  }
  PreParserExpression NewClassLiteralProperty(PreParserExpression key,
                                              PreParserExpression value,
                                              ClassLiteralProperty::Kind kind,
                                              bool is_static,
                                              bool is_computed_name) {
    return PreParserExpression::Default();
  }
  PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
                                               PreParserExpression value,
                                               ObjectLiteralProperty::Kind kind,
                                               bool is_computed_name) {
    return PreParserExpression::Default(value.variables_);
  }
  PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
                                               PreParserExpression value,
                                               bool is_computed_name) {
    return PreParserExpression::Default(value.variables_);
  }
  PreParserExpression NewObjectLiteral(PreParserExpressionList properties,
                                       int boilerplate_properties, int pos,
                                       bool has_rest_property) {
    return PreParserExpression::ObjectLiteral(properties.variables_);
  }
  PreParserExpression NewVariableProxy(void* variable) {
    return PreParserExpression::Default();
  }
  PreParserExpression NewProperty(PreParserExpression obj,
                                  PreParserExpression key,
                                  int pos) {
    if (obj.IsThis()) {
      return PreParserExpression::ThisProperty();
    }
    return PreParserExpression::Property();
  }
  PreParserExpression NewUnaryOperation(Token::Value op,
                                        PreParserExpression expression,
                                        int pos) {
    return PreParserExpression::Default();
  }
  PreParserExpression NewBinaryOperation(Token::Value op,
                                         PreParserExpression left,
                                         PreParserExpression right, int pos) {
    return PreParserExpression::BinaryOperation(left, op, right, zone_);
  }
  PreParserExpression NewCompareOperation(Token::Value op,
                                          PreParserExpression left,
                                          PreParserExpression right, int pos) {
    return PreParserExpression::Default();
  }
  PreParserExpression NewRewritableExpression(PreParserExpression expression) {
    return expression;
  }
  PreParserExpression NewAssignment(Token::Value op,
                                    PreParserExpression left,
                                    PreParserExpression right,
                                    int pos) {
    // Identifiers need to be tracked since this might be a parameter with a
    // default value inside an arrow function parameter list.
    return PreParserExpression::Assignment(left.variables_);
  }
  PreParserExpression NewYield(PreParserExpression expression, int pos,
                               Suspend::OnAbruptResume on_abrupt_resume) {
    return PreParserExpression::Default();
  }
  PreParserExpression NewAwait(PreParserExpression expression, int pos) {
    return PreParserExpression::Default();
  }
  PreParserExpression NewConditional(PreParserExpression condition,
                                     PreParserExpression then_expression,
                                     PreParserExpression else_expression,
                                     int pos) {
    return PreParserExpression::Default();
  }
  PreParserExpression NewCountOperation(Token::Value op,
                                        bool is_prefix,
                                        PreParserExpression expression,
                                        int pos) {
    return PreParserExpression::Default();
  }
  PreParserExpression NewCall(
      PreParserExpression expression, PreParserExpressionList arguments,
      int pos, Call::PossiblyEval possibly_eval = Call::NOT_EVAL) {
    if (possibly_eval == Call::IS_POSSIBLY_EVAL) {
      DCHECK(expression.IsIdentifier() && expression.AsIdentifier().IsEval());
      return PreParserExpression::CallEval();
    }
    return PreParserExpression::Call();
  }
  PreParserExpression NewCallNew(PreParserExpression expression,
                                 PreParserExpressionList arguments,
                                 int pos) {
    return PreParserExpression::Default();
  }
  PreParserStatement NewReturnStatement(
      PreParserExpression expression, int pos,
      int continuation_pos = kNoSourcePosition) {
    return PreParserStatement::Jump();
  }
  PreParserStatement NewAsyncReturnStatement(
      PreParserExpression expression, int pos,
      int continuation_pos = kNoSourcePosition) {
    return PreParserStatement::Jump();
  }
  PreParserExpression NewFunctionLiteral(
      PreParserIdentifier name, Scope* scope, PreParserStatementList body,
      int expected_property_count, int parameter_count, int function_length,
      FunctionLiteral::ParameterFlag has_duplicate_parameters,
      FunctionLiteral::FunctionType function_type,
      FunctionLiteral::EagerCompileHint eager_compile_hint, int position,
      bool has_braces, int function_literal_id,
      ProducedPreParsedScopeData* produced_preparsed_scope_data = nullptr) {
    DCHECK_NULL(produced_preparsed_scope_data);
    return PreParserExpression::Default();
  }

  PreParserExpression NewSpread(PreParserExpression expression, int pos,
                                int expr_pos) {
    return PreParserExpression::Spread(expression);
  }

  PreParserExpression NewEmptyParentheses(int pos) {
    return PreParserExpression::Default();
  }

  PreParserStatement NewEmptyStatement(int pos) {
    return PreParserStatement::Default();
  }

  PreParserStatement NewBlock(ZoneList<const AstRawString*>* labels,
                              int capacity, bool ignore_completion_value,
                              int pos) {
    return PreParserStatement::Default();
  }

  PreParserStatement NewDebuggerStatement(int pos) {
    return PreParserStatement::Default();
  }

  PreParserStatement NewExpressionStatement(PreParserExpression expr, int pos) {
    return PreParserStatement::ExpressionStatement(expr);
  }

  PreParserStatement NewIfStatement(PreParserExpression condition,
                                    PreParserStatement then_statement,
                                    PreParserStatement else_statement, int pos,
                                    SourceRange then_range = {},
                                    SourceRange else_range = {}) {
    // This must return a jump statement iff both clauses are jump statements.
    return else_statement.IsJumpStatement() ? then_statement : else_statement;
  }

  PreParserStatement NewBreakStatement(
      PreParserStatement target, int pos,
      int continuation_pos = kNoSourcePosition) {
    return PreParserStatement::Jump();
  }

  PreParserStatement NewContinueStatement(
      PreParserStatement target, int pos,
      int continuation_pos = kNoSourcePosition) {
    return PreParserStatement::Jump();
  }

  PreParserStatement NewWithStatement(Scope* scope,
                                      PreParserExpression expression,
                                      PreParserStatement statement, int pos) {
    return PreParserStatement::Default();
  }

  PreParserStatement NewDoWhileStatement(ZoneList<const AstRawString*>* labels,
                                         int pos) {
    return PreParserStatement::Default();
  }

  PreParserStatement NewWhileStatement(ZoneList<const AstRawString*>* labels,
                                       int pos) {
    return PreParserStatement::Default();
  }

  PreParserStatement NewSwitchStatement(ZoneList<const AstRawString*>* labels,
                                        int pos) {
    return PreParserStatement::Default();
  }

  PreParserStatement NewCaseClause(PreParserExpression label,
                                   PreParserStatementList statements, int pos) {
    return PreParserStatement::Default();
  }

  PreParserStatement NewForStatement(ZoneList<const AstRawString*>* labels,
                                     int pos) {
    return PreParserStatement::Default();
  }

  PreParserStatement NewForEachStatement(ForEachStatement::VisitMode visit_mode,
                                         ZoneList<const AstRawString*>* labels,
                                         int pos) {
    return PreParserStatement::Default();
  }

  PreParserStatement NewForOfStatement(ZoneList<const AstRawString*>* labels,
                                       int pos) {
    return PreParserStatement::Default();
  }

  PreParserExpression NewCallRuntime(Runtime::FunctionId id,
                                     ZoneList<PreParserExpression>* arguments,
                                     int pos) {
    return PreParserExpression::Default();
  }

  PreParserExpression NewImportCallExpression(PreParserExpression args,
                                              int pos) {
    return PreParserExpression::Default();
  }

  // Return the object itself as AstVisitor and implement the needed
  // dummy method right in this class.
  PreParserFactory* visitor() { return this; }
  int* ast_properties() {
    static int dummy = 42;
    return &dummy;
  }

 private:
  // For creating VariableProxy objects (if
  // PreParser::track_unresolved_variables_ is used).
  AstNodeFactory ast_node_factory_;
  Zone* zone_;
};


struct PreParserFormalParameters : FormalParametersBase {
  struct Parameter : public ZoneObject {
    Parameter(ZoneList<VariableProxy*>* variables, bool is_rest)
        : variables_(variables), is_rest(is_rest) {}
    Parameter** next() { return &next_parameter; }
    Parameter* const* next() const { return &next_parameter; }

    ZoneList<VariableProxy*>* variables_;
    Parameter* next_parameter = nullptr;
    bool is_rest : 1;
  };
  explicit PreParserFormalParameters(DeclarationScope* scope)
      : FormalParametersBase(scope) {}

  ThreadedList<Parameter> params;
};


class PreParser;

class PreParserTarget {
 public:
  PreParserTarget(ParserBase<PreParser>* preparser,
                  PreParserStatement statement) {}
};

class PreParserTargetScope {
 public:
  explicit PreParserTargetScope(ParserBase<PreParser>* preparser) {}
};

template <>
struct ParserTypes<PreParser> {
  typedef ParserBase<PreParser> Base;
  typedef PreParser Impl;

  // Return types for traversing functions.
  typedef PreParserIdentifier Identifier;
  typedef PreParserExpression Expression;
  typedef PreParserExpression FunctionLiteral;
  typedef PreParserExpression ObjectLiteralProperty;
  typedef PreParserExpression ClassLiteralProperty;
  typedef PreParserExpression Suspend;
  typedef PreParserExpressionList ExpressionList;
  typedef PreParserExpressionList ObjectPropertyList;
  typedef PreParserExpressionList ClassPropertyList;
  typedef PreParserFormalParameters FormalParameters;
  typedef PreParserStatement Statement;
  typedef PreParserStatementList StatementList;
  typedef PreParserStatement Block;
  typedef PreParserStatement BreakableStatement;
  typedef PreParserStatement IterationStatement;

  // For constructing objects returned by the traversing functions.
  typedef PreParserFactory Factory;

  typedef PreParserTarget Target;
  typedef PreParserTargetScope TargetScope;
};


// Preparsing checks a JavaScript program and emits preparse-data that helps
// a later parsing to be faster.
// See preparse-data-format.h for the data format.

// The PreParser checks that the syntax follows the grammar for JavaScript,
// and collects some information about the program along the way.
// The grammar check is only performed in order to understand the program
// sufficiently to deduce some information about it, that can be used
// to speed up later parsing. Finding errors is not the goal of pre-parsing,
// rather it is to speed up properly written and correct programs.
// That means that contextual checks (like a label being declared where
// it is used) are generally omitted.
class PreParser : public ParserBase<PreParser> {
  friend class ParserBase<PreParser>;
  friend class v8::internal::ExpressionClassifier<ParserTypes<PreParser>>;

 public:
  typedef PreParserIdentifier Identifier;
  typedef PreParserExpression Expression;
  typedef PreParserStatement Statement;

  enum PreParseResult {
    kPreParseStackOverflow,
    kPreParseAbort,
    kPreParseSuccess
  };

  PreParser(Zone* zone, Scanner* scanner, uintptr_t stack_limit,
            AstValueFactory* ast_value_factory,
            PendingCompilationErrorHandler* pending_error_handler,
            RuntimeCallStats* runtime_call_stats,
            bool parsing_on_main_thread = true)
      : ParserBase<PreParser>(zone, scanner, stack_limit, nullptr,
                              ast_value_factory, runtime_call_stats,
                              parsing_on_main_thread),
        use_counts_(nullptr),
        track_unresolved_variables_(false),
        pending_error_handler_(pending_error_handler),
        produced_preparsed_scope_data_(nullptr) {}

  static bool IsPreParser() { return true; }

  PreParserLogger* logger() { return &log_; }

  // Pre-parse the program from the character stream; returns true on
  // success (even if parsing failed, the pre-parse data successfully
  // captured the syntax error), and false if a stack-overflow happened
  // during parsing.
  PreParseResult PreParseProgram(bool is_module = false);

  // Parses a single function literal, from the opening parentheses before
  // parameters to the closing brace after the body.
  // Returns a FunctionEntry describing the body of the function in enough
  // detail that it can be lazily compiled.
  // The scanner is expected to have matched the "function" or "function*"
  // keyword and parameters, and have consumed the initial '{'.
  // At return, unless an error occurred, the scanner is positioned before the
  // the final '}'.
  PreParseResult PreParseFunction(
      const AstRawString* function_name, FunctionKind kind,
      FunctionLiteral::FunctionType function_type,
      DeclarationScope* function_scope, bool parsing_module,
      bool track_unresolved_variables, bool may_abort, int* use_counts,
      ProducedPreParsedScopeData** produced_preparser_scope_data);

  ProducedPreParsedScopeData* produced_preparsed_scope_data() const {
    return produced_preparsed_scope_data_;
  }

  void set_produced_preparsed_scope_data(
      ProducedPreParsedScopeData* produced_preparsed_scope_data) {
    produced_preparsed_scope_data_ = produced_preparsed_scope_data;
  }

 private:
  // These types form an algebra over syntactic categories that is just
  // rich enough to let us recognize and propagate the constructs that
  // are either being counted in the preparser data, or is important
  // to throw the correct syntax error exceptions.

  // All ParseXXX functions take as the last argument an *ok parameter
  // which is set to false if parsing failed; it is unchanged otherwise.
  // By making the 'exception handling' explicit, we are forced to check
  // for failure at the call sites.

  // Indicates that we won't switch from the preparser to the preparser; we'll
  // just stay where we are.
  bool AllowsLazyParsingWithoutUnresolvedVariables() const { return false; }
  bool parse_lazily() const { return false; }

  V8_INLINE LazyParsingResult
  SkipFunction(const AstRawString* name, FunctionKind kind,
               FunctionLiteral::FunctionType function_type,
               DeclarationScope* function_scope, int* num_parameters,
               ProducedPreParsedScopeData** produced_preparsed_scope_data,
               bool is_inner_function, bool may_abort, bool* ok) {
    UNREACHABLE();
  }
  Expression ParseFunctionLiteral(
      Identifier name, Scanner::Location function_name_location,
      FunctionNameValidity function_name_validity, FunctionKind kind,
      int function_token_pos, FunctionLiteral::FunctionType function_type,
      LanguageMode language_mode, bool* ok);
  LazyParsingResult ParseStatementListAndLogFunction(
      PreParserFormalParameters* formals, bool maybe_abort, bool* ok);

  struct TemplateLiteralState {};

  V8_INLINE TemplateLiteralState OpenTemplateLiteral(int pos) {
    return TemplateLiteralState();
  }
  V8_INLINE void AddTemplateExpression(TemplateLiteralState* state,
                                       PreParserExpression expression) {}
  V8_INLINE void AddTemplateSpan(TemplateLiteralState* state, bool should_cook,
                                 bool tail) {}
  V8_INLINE PreParserExpression CloseTemplateLiteral(
      TemplateLiteralState* state, int start, PreParserExpression tag);
  V8_INLINE void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {}

  V8_INLINE void SetLanguageMode(Scope* scope, LanguageMode mode) {
    scope->SetLanguageMode(mode);
  }
  V8_INLINE void SetAsmModule() {}

  V8_INLINE void MarkCollectedTailCallExpressions() {}
  V8_INLINE void MarkTailPosition(PreParserExpression expression) {}

  V8_INLINE PreParserExpression SpreadCall(PreParserExpression function,
                                           PreParserExpressionList args,
                                           int pos,
                                           Call::PossiblyEval possibly_eval);
  V8_INLINE PreParserExpression SpreadCallNew(PreParserExpression function,
                                              PreParserExpressionList args,
                                              int pos);

  V8_INLINE void RewriteDestructuringAssignments() {}

  V8_INLINE PreParserExpression RewriteExponentiation(PreParserExpression left,
                                                      PreParserExpression right,
                                                      int pos) {
    return left;
  }
  V8_INLINE PreParserExpression RewriteAssignExponentiation(
      PreParserExpression left, PreParserExpression right, int pos) {
    return left;
  }

  V8_INLINE void PrepareAsyncFunctionBody(PreParserStatementList body,
                                          FunctionKind kind, int pos) {}
  V8_INLINE void RewriteAsyncFunctionBody(PreParserStatementList body,
                                          PreParserStatement block,
                                          PreParserExpression return_value,
                                          bool* ok) {}
  V8_INLINE PreParserExpression RewriteYieldStar(PreParserExpression expression,
                                                 int pos) {
    return PreParserExpression::Default();
  }
  V8_INLINE void RewriteNonPattern(bool* ok) { ValidateExpression(ok); }

  void DeclareAndInitializeVariables(
      PreParserStatement block,
      const DeclarationDescriptor* declaration_descriptor,
      const DeclarationParsingResult::Declaration* declaration,
      ZoneList<const AstRawString*>* names, bool* ok);

  V8_INLINE ZoneList<const AstRawString*>* DeclareLabel(
      ZoneList<const AstRawString*>* labels, PreParserExpression expr,
      bool* ok) {
    DCHECK(!expr.AsIdentifier().IsEnum());
    DCHECK(!parsing_module_ || !expr.AsIdentifier().IsAwait());
    DCHECK(IsIdentifier(expr));
    return labels;
  }

  // TODO(nikolaos): The preparser currently does not keep track of labels.
  V8_INLINE bool ContainsLabel(ZoneList<const AstRawString*>* labels,
                               PreParserIdentifier label) {
    return false;
  }

  V8_INLINE PreParserExpression RewriteReturn(PreParserExpression return_value,
                                              int pos) {
    return return_value;
  }
  V8_INLINE PreParserStatement RewriteSwitchStatement(
      PreParserExpression tag, PreParserStatement switch_statement,
      PreParserStatementList cases, Scope* scope) {
    return PreParserStatement::Default();
  }

  V8_INLINE void RewriteCatchPattern(CatchInfo* catch_info, bool* ok) {
    if (track_unresolved_variables_) {
      const AstRawString* catch_name = catch_info->name.string_;
      if (catch_name == nullptr) {
        catch_name = ast_value_factory()->dot_catch_string();
      }
      // Unlike in the parser, we need to declare the catch variable as LET
      // variable, so that it won't get hoisted out of the scope. (Parser uses
      // DeclareLocal instead of DeclareVariable to prevent hoisting.) Another
      // solution would've been to add DeclareLocalName just for this purpose.
      catch_info->scope->DeclareVariableName(catch_name, LET);

      if (catch_info->pattern.variables_ != nullptr) {
        for (auto variable : *catch_info->pattern.variables_) {
          scope()->DeclareVariableName(variable->raw_name(), LET);
        }
      }
    }
  }

  V8_INLINE void ValidateCatchBlock(const CatchInfo& catch_info, bool* ok) {}
  V8_INLINE PreParserStatement RewriteTryStatement(
      PreParserStatement try_block, PreParserStatement catch_block,
      const SourceRange& catch_range, PreParserStatement finally_block,
      const SourceRange& finally_range, const CatchInfo& catch_info, int pos) {
    return PreParserStatement::Default();
  }

  V8_INLINE void ParseAndRewriteGeneratorFunctionBody(
      int pos, FunctionKind kind, PreParserStatementList body, bool* ok) {
    ParseStatementList(body, Token::RBRACE, ok);
  }
  V8_INLINE void ParseAndRewriteAsyncGeneratorFunctionBody(
      int pos, FunctionKind kind, PreParserStatementList body, bool* ok) {
    ParseStatementList(body, Token::RBRACE, ok);
  }
  V8_INLINE void CreateFunctionNameAssignment(
      const AstRawString* function_name,
      FunctionLiteral::FunctionType function_type,
      DeclarationScope* function_scope) {
    if (track_unresolved_variables_ &&
        function_type == FunctionLiteral::kNamedExpression) {
      if (function_scope->LookupLocal(function_name) == nullptr) {
        DCHECK_EQ(function_scope, scope());
        Variable* fvar = function_scope->DeclareFunctionVar(function_name);
        fvar->set_is_used();
      }
    }
  }

  V8_INLINE void CreateFunctionNameAssignment(
      PreParserIdentifier function_name, int pos,
      FunctionLiteral::FunctionType function_type,
      DeclarationScope* function_scope, PreParserStatementList result,
      int index) {
    CreateFunctionNameAssignment(function_name.string_, function_type,
                                 function_scope);
  }

  V8_INLINE PreParserExpression RewriteDoExpression(PreParserStatement body,
                                                    int pos, bool* ok) {
    return PreParserExpression::Default();
  }

  // TODO(nikolaos): The preparser currently does not keep track of labels
  // and targets.
  V8_INLINE PreParserStatement LookupBreakTarget(PreParserIdentifier label,
                                                 bool* ok) {
    return PreParserStatement::Default();
  }
  V8_INLINE PreParserStatement LookupContinueTarget(PreParserIdentifier label,
                                                    bool* ok) {
    return PreParserStatement::Default();
  }

  V8_INLINE PreParserStatement DeclareFunction(
      PreParserIdentifier variable_name, PreParserExpression function,
      VariableMode mode, int pos, bool is_sloppy_block_function,
      ZoneList<const AstRawString*>* names, bool* ok) {
    DCHECK_NULL(names);
    if (variable_name.string_ != nullptr) {
      DCHECK(track_unresolved_variables_);
      scope()->DeclareVariableName(variable_name.string_, mode);
      if (is_sloppy_block_function) {
        GetDeclarationScope()->DeclareSloppyBlockFunction(variable_name.string_,
                                                          scope());
      }
    }
    return Statement::Default();
  }

  V8_INLINE PreParserStatement
  DeclareClass(PreParserIdentifier variable_name, PreParserExpression value,
               ZoneList<const AstRawString*>* names, int class_token_pos,
               int end_pos, bool* ok) {
    // Preparser shouldn't be used in contexts where we need to track the names.
    DCHECK_NULL(names);
    if (variable_name.string_ != nullptr) {
      DCHECK(track_unresolved_variables_);
      scope()->DeclareVariableName(variable_name.string_, LET);
    }
    return PreParserStatement::Default();
  }
  V8_INLINE void DeclareClassVariable(PreParserIdentifier name,
                                      ClassInfo* class_info,
                                      int class_token_pos, bool* ok) {
    if (name.string_ != nullptr) {
      DCHECK(track_unresolved_variables_);
      scope()->DeclareVariableName(name.string_, CONST);
    }
  }
  V8_INLINE void DeclareClassProperty(PreParserIdentifier class_name,
                                      PreParserExpression property,
                                      ClassLiteralProperty::Kind kind,
                                      bool is_static, bool is_constructor,
                                      ClassInfo* class_info, bool* ok) {
  }
  V8_INLINE PreParserExpression RewriteClassLiteral(Scope* scope,
                                                    PreParserIdentifier name,
                                                    ClassInfo* class_info,
                                                    int pos, int end_pos,
                                                    bool* ok) {
    bool has_default_constructor = !class_info->has_seen_constructor;
    // Account for the default constructor.
    if (has_default_constructor) GetNextFunctionLiteralId();
    return PreParserExpression::Default();
  }

  V8_INLINE PreParserStatement DeclareNative(PreParserIdentifier name, int pos,
                                             bool* ok) {
    return PreParserStatement::Default();
  }

  V8_INLINE void QueueDestructuringAssignmentForRewriting(
      PreParserExpression assignment) {}
  V8_INLINE void QueueNonPatternForRewriting(PreParserExpression expr,
                                             bool* ok) {}

  // Helper functions for recursive descent.
  V8_INLINE bool IsEval(PreParserIdentifier identifier) const {
    return identifier.IsEval();
  }

  V8_INLINE bool IsArguments(PreParserIdentifier identifier) const {
    return identifier.IsArguments();
  }

  V8_INLINE bool IsEvalOrArguments(PreParserIdentifier identifier) const {
    return identifier.IsEvalOrArguments();
  }

  V8_INLINE bool IsUndefined(PreParserIdentifier identifier) const {
    return identifier.IsUndefined();
  }

  V8_INLINE bool IsAwait(PreParserIdentifier identifier) const {
    return identifier.IsAwait();
  }

  // Returns true if the expression is of type "this.foo".
  V8_INLINE static bool IsThisProperty(PreParserExpression expression) {
    return expression.IsThisProperty();
  }

  V8_INLINE static bool IsIdentifier(PreParserExpression expression) {
    return expression.IsIdentifier();
  }

  V8_INLINE static PreParserIdentifier AsIdentifier(
      PreParserExpression expression) {
    return expression.AsIdentifier();
  }

  V8_INLINE static PreParserExpression AsIdentifierExpression(
      PreParserExpression expression) {
    return expression;
  }

  V8_INLINE bool IsPrototype(PreParserIdentifier identifier) const {
    return identifier.IsPrototype();
  }

  V8_INLINE bool IsConstructor(PreParserIdentifier identifier) const {
    return identifier.IsConstructor();
  }

  V8_INLINE bool IsName(PreParserIdentifier identifier) const {
    return identifier.IsName();
  }

  V8_INLINE static bool IsBoilerplateProperty(PreParserExpression property) {
    // PreParser doesn't count boilerplate properties.
    return false;
  }

  V8_INLINE bool IsNative(PreParserExpression expr) const {
    // Preparsing is disabled for extensions (because the extension
    // details aren't passed to lazily compiled functions), so we
    // don't accept "native function" in the preparser and there is
    // no need to keep track of "native".
    return false;
  }

  V8_INLINE static bool IsArrayIndex(PreParserIdentifier string,
                                     uint32_t* index) {
    return false;
  }

  V8_INLINE bool IsUseStrictDirective(PreParserStatement statement) const {
    return statement.IsUseStrictLiteral();
  }

  V8_INLINE bool IsUseAsmDirective(PreParserStatement statement) const {
    return statement.IsUseAsmLiteral();
  }

  V8_INLINE bool IsStringLiteral(PreParserStatement statement) const {
    return statement.IsStringLiteral();
  }

  V8_INLINE static PreParserExpression GetPropertyValue(
      PreParserExpression property) {
    return PreParserExpression::Default();
  }

  V8_INLINE static void GetDefaultStrings(
      PreParserIdentifier* default_string,
      PreParserIdentifier* star_default_star_string) {}

  // Functions for encapsulating the differences between parsing and preparsing;
  // operations interleaved with the recursive descent.
  V8_INLINE static void PushLiteralName(PreParserIdentifier id) {}
  V8_INLINE static void PushVariableName(PreParserIdentifier id) {}
  V8_INLINE void PushPropertyName(PreParserExpression expression) {}
  V8_INLINE void PushEnclosingName(PreParserIdentifier name) {}
  V8_INLINE static void AddFunctionForNameInference(
      PreParserExpression expression) {}
  V8_INLINE static void InferFunctionName() {}

  V8_INLINE static void CheckAssigningFunctionLiteralToProperty(
      PreParserExpression left, PreParserExpression right) {}

  V8_INLINE void MarkExpressionAsAssigned(PreParserExpression expression) {
    // TODO(marja): To be able to produce the same errors, the preparser needs
    // to start tracking which expressions are variables and which are assigned.
    if (expression.variables_ != nullptr) {
      DCHECK(FLAG_lazy_inner_functions);
      DCHECK(track_unresolved_variables_);
      for (auto variable : *expression.variables_) {
        variable->set_is_assigned();
      }
    }
  }

  V8_INLINE bool ShortcutNumericLiteralBinaryExpression(PreParserExpression* x,
                                                        PreParserExpression y,
                                                        Token::Value op,
                                                        int pos) {
    return false;
  }

  V8_INLINE PreParserExpression BuildUnaryExpression(
      PreParserExpression expression, Token::Value op, int pos) {
    return PreParserExpression::Default();
  }

  V8_INLINE PreParserStatement
  BuildInitializationBlock(DeclarationParsingResult* parsing_result,
                           ZoneList<const AstRawString*>* names, bool* ok) {
    for (auto declaration : parsing_result->declarations) {
      DeclareAndInitializeVariables(PreParserStatement::Default(),
                                    &(parsing_result->descriptor), &declaration,
                                    names, ok);
    }
    return PreParserStatement::Default();
  }

  V8_INLINE PreParserStatement InitializeForEachStatement(
      PreParserStatement stmt, PreParserExpression each,
      PreParserExpression subject, PreParserStatement body) {
    MarkExpressionAsAssigned(each);
    return stmt;
  }

  V8_INLINE PreParserStatement InitializeForOfStatement(
      PreParserStatement stmt, PreParserExpression each,
      PreParserExpression iterable, PreParserStatement body, bool finalize,
      IteratorType type, int next_result_pos = kNoSourcePosition) {
    MarkExpressionAsAssigned(each);
    return stmt;
  }

  V8_INLINE PreParserStatement RewriteForVarInLegacy(const ForInfo& for_info) {
    return PreParserStatement::Null();
  }

  V8_INLINE void DesugarBindingInForEachStatement(
      ForInfo* for_info, PreParserStatement* body_block,
      PreParserExpression* each_variable, bool* ok) {
    if (track_unresolved_variables_) {
      DCHECK(for_info->parsing_result.declarations.length() == 1);
      bool is_for_var_of =
          for_info->mode == ForEachStatement::ITERATE &&
          for_info->parsing_result.descriptor.mode == VariableMode::VAR;
      bool collect_names =
          IsLexicalVariableMode(for_info->parsing_result.descriptor.mode) ||
          is_for_var_of;

      DeclareAndInitializeVariables(
          PreParserStatement::Default(), &for_info->parsing_result.descriptor,
          &for_info->parsing_result.declarations[0],
          collect_names ? &for_info->bound_names : nullptr, ok);
    }
  }

  V8_INLINE PreParserStatement CreateForEachStatementTDZ(
      PreParserStatement init_block, const ForInfo& for_info, bool* ok) {
    if (track_unresolved_variables_) {
      if (IsLexicalVariableMode(for_info.parsing_result.descriptor.mode)) {
        for (auto name : for_info.bound_names) {
          scope()->DeclareVariableName(name, LET);
        }
        return PreParserStatement::Default();
      }
    }
    return init_block;
  }

  V8_INLINE StatementT DesugarLexicalBindingsInForStatement(
      PreParserStatement loop, PreParserStatement init,
      PreParserExpression cond, PreParserStatement next,
      PreParserStatement body, const SourceRange& body_range,
      Scope* inner_scope, const ForInfo& for_info, bool* ok) {
    // See Parser::DesugarLexicalBindingsInForStatement.
    if (track_unresolved_variables_) {
      for (auto name : for_info.bound_names) {
        inner_scope->DeclareVariableName(
            name, for_info.parsing_result.descriptor.mode);
      }
    }
    return loop;
  }

  V8_INLINE PreParserStatement BuildParameterInitializationBlock(
      const PreParserFormalParameters& parameters, bool* ok) {
    return PreParserStatement::Default();
  }

  V8_INLINE PreParserStatement
  BuildRejectPromiseOnException(PreParserStatement init_block) {
    return PreParserStatement::Default();
  }

  V8_INLINE void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) {
    scope->HoistSloppyBlockFunctions(nullptr);
  }

  V8_INLINE void InsertShadowingVarBindingInitializers(
      PreParserStatement block) {}

  V8_INLINE PreParserExpression
  NewThrowReferenceError(MessageTemplate::Template message, int pos) {
    return PreParserExpression::Default();
  }

  V8_INLINE PreParserExpression NewThrowSyntaxError(
      MessageTemplate::Template message, PreParserIdentifier arg, int pos) {
    return PreParserExpression::Default();
  }

  V8_INLINE PreParserExpression NewThrowTypeError(
      MessageTemplate::Template message, PreParserIdentifier arg, int pos) {
    return PreParserExpression::Default();
  }

  // Reporting errors.
  V8_INLINE void ReportMessageAt(Scanner::Location source_location,
                                 MessageTemplate::Template message,
                                 const char* arg = NULL,
                                 ParseErrorType error_type = kSyntaxError) {
    pending_error_handler_->ReportMessageAt(source_location.beg_pos,
                                            source_location.end_pos, message,
                                            arg, error_type);
  }

  V8_INLINE void ReportMessageAt(Scanner::Location source_location,
                                 MessageTemplate::Template message,
                                 PreParserIdentifier arg,
                                 ParseErrorType error_type = kSyntaxError) {
    UNREACHABLE();
  }

  // "null" return type creators.
  V8_INLINE static PreParserIdentifier EmptyIdentifier() {
    return PreParserIdentifier::Empty();
  }
  V8_INLINE static bool IsEmptyIdentifier(PreParserIdentifier name) {
    return name.IsEmpty();
  }
  V8_INLINE static PreParserExpression EmptyExpression() {
    return PreParserExpression::Empty();
  }
  V8_INLINE static PreParserExpression EmptyLiteral() {
    return PreParserExpression::Default();
  }
  V8_INLINE static PreParserExpression EmptyObjectLiteralProperty() {
    return PreParserExpression::Default();
  }
  V8_INLINE static PreParserExpression EmptyClassLiteralProperty() {
    return PreParserExpression::Default();
  }
  V8_INLINE static PreParserExpression EmptyFunctionLiteral() {
    return PreParserExpression::Default();
  }

  V8_INLINE static bool IsEmptyExpression(PreParserExpression expr) {
    return expr.IsEmpty();
  }

  V8_INLINE static PreParserExpressionList NullExpressionList() {
    return PreParserExpressionList::Null();
  }

  V8_INLINE static bool IsNullExpressionList(PreParserExpressionList exprs) {
    return exprs.IsNull();
  }

  V8_INLINE static PreParserStatementList NullStatementList() {
    return PreParserStatementList::Null();
  }

  V8_INLINE static bool IsNullStatementList(PreParserStatementList stmts) {
    return stmts.IsNull();
  }

  V8_INLINE static PreParserStatement NullStatement() {
    return PreParserStatement::Null();
  }

  V8_INLINE bool IsNullStatement(PreParserStatement stmt) {
    return stmt.IsNullStatement();
  }

  V8_INLINE bool IsEmptyStatement(PreParserStatement stmt) {
    return stmt.IsEmptyStatement();
  }

  V8_INLINE static PreParserStatement NullBlock() {
    return PreParserStatement::Null();
  }

  V8_INLINE PreParserIdentifier EmptyIdentifierString() const {
    return PreParserIdentifier::Default();
  }

  // Odd-ball literal creators.
  V8_INLINE PreParserExpression GetLiteralTheHole(int position) {
    return PreParserExpression::Default();
  }

  V8_INLINE PreParserExpression GetLiteralUndefined(int position) {
    return PreParserExpression::Default();
  }

  // Producing data during the recursive descent.
  PreParserIdentifier GetSymbol() const;

  V8_INLINE PreParserIdentifier GetNextSymbol() const {
    return PreParserIdentifier::Default();
  }

  V8_INLINE PreParserIdentifier GetNumberAsSymbol() const {
    return PreParserIdentifier::Default();
  }

  V8_INLINE PreParserExpression ThisExpression(int pos = kNoSourcePosition) {
    ZoneList<VariableProxy*>* variables = nullptr;
    if (track_unresolved_variables_) {
      VariableProxy* proxy = scope()->NewUnresolved(
          factory()->ast_node_factory(), ast_value_factory()->this_string(),
          pos, THIS_VARIABLE);

      variables = new (zone()) ZoneList<VariableProxy*>(1, zone());
      variables->Add(proxy, zone());
    }
    return PreParserExpression::This(variables);
  }

  V8_INLINE PreParserExpression NewSuperPropertyReference(int pos) {
    if (track_unresolved_variables_) {
      scope()->NewUnresolved(factory()->ast_node_factory(),
                             ast_value_factory()->this_function_string(), pos,
                             NORMAL_VARIABLE);
      scope()->NewUnresolved(factory()->ast_node_factory(),
                             ast_value_factory()->this_string(), pos,
                             THIS_VARIABLE);
    }
    return PreParserExpression::Default();
  }

  V8_INLINE PreParserExpression NewSuperCallReference(int pos) {
    if (track_unresolved_variables_) {
      scope()->NewUnresolved(factory()->ast_node_factory(),
                             ast_value_factory()->this_function_string(), pos,
                             NORMAL_VARIABLE);
      scope()->NewUnresolved(factory()->ast_node_factory(),
                             ast_value_factory()->new_target_string(), pos,
                             NORMAL_VARIABLE);
      scope()->NewUnresolved(factory()->ast_node_factory(),
                             ast_value_factory()->this_string(), pos,
                             THIS_VARIABLE);
    }
    return PreParserExpression::SuperCallReference();
  }

  V8_INLINE PreParserExpression NewTargetExpression(int pos) {
    return PreParserExpression::NewTargetExpression();
  }

  V8_INLINE PreParserExpression FunctionSentExpression(int pos) {
    return PreParserExpression::Default();
  }

  V8_INLINE PreParserExpression ExpressionFromLiteral(Token::Value token,
                                                      int pos) {
    return PreParserExpression::Default();
  }

  PreParserExpression ExpressionFromIdentifier(
      PreParserIdentifier name, int start_position,
      InferName infer = InferName::kYes);

  V8_INLINE PreParserExpression ExpressionFromString(int pos) {
    if (scanner()->IsUseStrict()) {
      return PreParserExpression::UseStrictStringLiteral();
    }
    return PreParserExpression::StringLiteral();
  }

  V8_INLINE PreParserExpressionList NewExpressionList(int size) const {
    return PreParserExpressionList();
  }

  V8_INLINE PreParserExpressionList NewObjectPropertyList(int size) const {
    return PreParserExpressionList();
  }

  V8_INLINE PreParserExpressionList NewClassPropertyList(int size) const {
    return PreParserExpressionList();
  }

  V8_INLINE PreParserStatementList NewStatementList(int size) const {
    return PreParserStatementList();
  }

  PreParserStatementList NewCaseClauseList(int size) {
    return PreParserStatementList();
  }

  V8_INLINE PreParserExpression
  NewV8Intrinsic(PreParserIdentifier name, PreParserExpressionList arguments,
                 int pos, bool* ok) {
    return PreParserExpression::Default();
  }

  V8_INLINE PreParserStatement NewThrowStatement(PreParserExpression exception,
                                                 int pos) {
    return PreParserStatement::Jump();
  }

  V8_INLINE void AddParameterInitializationBlock(
      const PreParserFormalParameters& parameters, PreParserStatementList body,
      bool is_async, bool* ok) {}

  V8_INLINE void AddFormalParameter(PreParserFormalParameters* parameters,
                                    PreParserExpression pattern,
                                    PreParserExpression initializer,
                                    int initializer_end_position,
                                    bool is_rest) {
    if (track_unresolved_variables_) {
      DCHECK(FLAG_lazy_inner_functions);
      parameters->params.Add(new (zone()) PreParserFormalParameters::Parameter(
          pattern.variables_, is_rest));
    }
    parameters->UpdateArityAndFunctionLength(!initializer.IsEmpty(), is_rest);
  }

  V8_INLINE void DeclareFormalParameters(
      DeclarationScope* scope,
      const ThreadedList<PreParserFormalParameters::Parameter>& parameters,
      bool is_simple) {
    if (!is_simple) scope->SetHasNonSimpleParameters();
    if (track_unresolved_variables_) {
      DCHECK(FLAG_lazy_inner_functions);
      for (auto parameter : parameters) {
        DCHECK_IMPLIES(is_simple, parameter->variables_ != nullptr);
        DCHECK_IMPLIES(is_simple, parameter->variables_->length() == 1);
        // Make sure each parameter is added only once even if it's a
        // destructuring parameter which contains multiple names.
        bool add_parameter = true;
        if (parameter->variables_ != nullptr) {
          for (auto variable : (*parameter->variables_)) {
            // We declare the parameter name for all names, but only create a
            // parameter entry for the first one.
            scope->DeclareParameterName(variable->raw_name(),
                                        parameter->is_rest, ast_value_factory(),
                                        true, add_parameter);
            add_parameter = false;
          }
        }
        if (add_parameter) {
          // No names were declared; declare a dummy one here to up the
          // parameter count.
          DCHECK(!is_simple);
          scope->DeclareParameterName(ast_value_factory()->empty_string(),
                                      parameter->is_rest, ast_value_factory(),
                                      false, add_parameter);
        }
      }
    }
  }

  V8_INLINE void DeclareArrowFunctionFormalParameters(
      PreParserFormalParameters* parameters, PreParserExpression params,
      const Scanner::Location& params_loc, Scanner::Location* duplicate_loc,
      bool* ok) {
    // TODO(wingo): Detect duplicated identifiers in paramlists.  Detect
    // parameter lists that are too long.
    if (track_unresolved_variables_) {
      DCHECK(FLAG_lazy_inner_functions);
      if (params.variables_ != nullptr) {
        for (auto variable : *params.variables_) {
          parameters->scope->DeclareVariableName(variable->raw_name(), VAR);
        }
      }
    }
  }

  V8_INLINE PreParserExpression NoTemplateTag() {
    return PreParserExpression::NoTemplateTag();
  }

  V8_INLINE static bool IsTaggedTemplate(const PreParserExpression tag) {
    return !tag.IsNoTemplateTag();
  }

  V8_INLINE PreParserExpression
  ExpressionListToExpression(PreParserExpressionList args) {
    return PreParserExpression::Default(args.variables_);
  }

  V8_INLINE void SetFunctionNameFromPropertyName(
      PreParserExpression property, PreParserIdentifier name,
      const AstRawString* prefix = nullptr) {}
  V8_INLINE void SetFunctionNameFromIdentifierRef(
      PreParserExpression value, PreParserExpression identifier) {}

  V8_INLINE ZoneList<typename ExpressionClassifier::Error>*
  GetReportedErrorList() const {
    return function_state_->GetReportedErrorList();
  }

  V8_INLINE ZoneList<PreParserExpression>* GetNonPatternList() const {
    return function_state_->non_patterns_to_rewrite();
  }

  V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) {
    if (use_counts_ != nullptr) ++use_counts_[feature];
  }

  V8_INLINE bool ParsingDynamicFunctionDeclaration() const { return false; }

  V8_INLINE void RecordBlockSourceRange(PreParserStatement node,
                                        int32_t continuation_position) {}
  V8_INLINE void RecordCaseClauseSourceRange(PreParserStatement node,
                                             const SourceRange& body_range) {}
  V8_INLINE void RecordConditionalSourceRange(PreParserExpression node,
                                              const SourceRange& then_range,
                                              const SourceRange& else_range) {}
  V8_INLINE void RecordIfStatementSourceRange(PreParserStatement node,
                                              const SourceRange& then_range,
                                              const SourceRange& else_range) {}
  V8_INLINE void RecordJumpStatementSourceRange(PreParserStatement node,
                                                int32_t continuation_position) {
  }
  V8_INLINE void RecordIterationStatementSourceRange(
      PreParserStatement node, const SourceRange& body_range) {}
  V8_INLINE void RecordSwitchStatementSourceRange(
      PreParserStatement node, int32_t continuation_position) {}
  V8_INLINE void RecordThrowSourceRange(PreParserStatement node,
                                        int32_t continuation_position) {}
  V8_INLINE void RecordTryCatchStatementSourceRange(
      PreParserStatement node, const SourceRange& body_range) {}
  V8_INLINE void RecordTryFinallyStatementSourceRange(
      PreParserStatement node, const SourceRange& body_range) {}

  // Preparser's private field members.

  int* use_counts_;
  bool track_unresolved_variables_;
  PreParserLogger log_;
  PendingCompilationErrorHandler* pending_error_handler_;

  ProducedPreParsedScopeData* produced_preparsed_scope_data_;
};

PreParserExpression PreParser::SpreadCall(PreParserExpression function,
                                          PreParserExpressionList args, int pos,
                                          Call::PossiblyEval possibly_eval) {
  return factory()->NewCall(function, args, pos, possibly_eval);
}

PreParserExpression PreParser::SpreadCallNew(PreParserExpression function,
                                             PreParserExpressionList args,
                                             int pos) {
  return factory()->NewCallNew(function, args, pos);
}

PreParserExpression PreParser::CloseTemplateLiteral(TemplateLiteralState* state,
                                                    int start,
                                                    PreParserExpression tag) {
  return EmptyExpression();
}

}  // namespace internal
}  // namespace v8

#endif  // V8_PARSING_PREPARSER_H
