text: // 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_AST_AST_H_
  #define V8_AST_AST_H_
  
  #include <memory>
  
  #include "src/ast/ast-value-factory.h"
  #include "src/ast/modules.h"
  #include "src/ast/variables.h"
  #include "src/bailout-reason.h"
  #include "src/globals.h"
  #include "src/heap/factory.h"
  #include "src/isolate.h"
  #include "src/label.h"
  #include "src/objects/literal-objects.h"
  #include "src/objects/smi.h"
  #include "src/parsing/token.h"
  #include "src/runtime/runtime.h"
  
  namespace v8 {
  namespace internal {
  
  // The abstract syntax tree is an intermediate, light-weight
  // representation of the parsed JavaScript code suitable for
  // compilation to native code.
  
  // Nodes are allocated in a separate zone, which allows faster
  // allocation and constant-time deallocation of the entire syntax
  // tree.
  
  
  // ----------------------------------------------------------------------------
  // Nodes of the abstract syntax tree. Only concrete classes are
  // enumerated here.
  
  #define DECLARATION_NODE_LIST(V) \
    V(VariableDeclaration)         \
    V(FunctionDeclaration)
  
  #define ITERATION_NODE_LIST(V) \
    V(DoWhileStatement)          \
    V(WhileStatement)            \
    V(ForStatement)              \
    V(ForInStatement)            \
    V(ForOfStatement)
  
  #define BREAKABLE_NODE_LIST(V) \
    V(Block)                     \
    V(SwitchStatement)
  
  #define STATEMENT_NODE_LIST(V)    \
    ITERATION_NODE_LIST(V)          \
    BREAKABLE_NODE_LIST(V)          \
    V(ExpressionStatement)          \
    V(EmptyStatement)               \
    V(SloppyBlockFunctionStatement) \
    V(IfStatement)                  \
    V(ContinueStatement)            \
    V(BreakStatement)               \
    V(ReturnStatement)              \
    V(WithStatement)                \
    V(TryCatchStatement)            \
    V(TryFinallyStatement)          \
    V(DebuggerStatement)            \
    V(InitializeClassMembersStatement)
  
  #define LITERAL_NODE_LIST(V) \
    V(RegExpLiteral)           \
    V(ObjectLiteral)           \
    V(ArrayLiteral)
  
  #define EXPRESSION_NODE_LIST(V) \
    LITERAL_NODE_LIST(V)          \
    V(Assignment)                 \
    V(Await)                      \
    V(BinaryOperation)            \
    V(NaryOperation)              \
    V(Call)                       \
    V(CallNew)                    \
    V(CallRuntime)                \
    V(ClassLiteral)               \
    V(CompareOperation)           \
    V(CompoundAssignment)         \
    V(Conditional)                \
    V(CountOperation)             \
    V(DoExpression)               \
    V(EmptyParentheses)           \
    V(FunctionLiteral)            \
    V(GetTemplateObject)          \
    V(ImportCallExpression)       \
    V(Literal)                    \
    V(NativeFunctionLiteral)      \
    V(Property)                   \
    V(ResolvedProperty)           \
    V(Spread)                     \
    V(StoreInArrayLiteral)        \
    V(SuperCallReference)         \
    V(SuperPropertyReference)     \
    V(TemplateLiteral)            \
    V(ThisExpression)             \
    V(Throw)                      \
    V(UnaryOperation)             \
    V(VariableProxy)              \
    V(Yield)                      \
    V(YieldStar)
  
  #define FAILURE_NODE_LIST(V) V(FailureExpression)
  
  #define AST_NODE_LIST(V)                        \
    DECLARATION_NODE_LIST(V)                      \
    STATEMENT_NODE_LIST(V)                        \
    EXPRESSION_NODE_LIST(V)
  
  // Forward declarations
  class AstNode;
  class AstNodeFactory;
  class Declaration;
  class BreakableStatement;
  class Expression;
  class IterationStatement;
  class MaterializedLiteral;
  class NestedVariableDeclaration;
  class ProducedPreparseData;
  class Statement;
  
  #define DEF_FORWARD_DECLARATION(type) class type;
  AST_NODE_LIST(DEF_FORWARD_DECLARATION)
  FAILURE_NODE_LIST(DEF_FORWARD_DECLARATION)
  #undef DEF_FORWARD_DECLARATION
  
  class AstNode: public ZoneObject {
   public:
  #define DECLARE_TYPE_ENUM(type) k##type,
    enum NodeType : uint8_t {
      AST_NODE_LIST(DECLARE_TYPE_ENUM) /* , */
      FAILURE_NODE_LIST(DECLARE_TYPE_ENUM)
    };
  #undef DECLARE_TYPE_ENUM
  
    void* operator new(size_t size, Zone* zone) { return zone->New(size); }
  
    NodeType node_type() const { return NodeTypeField::decode(bit_field_); }
    int position() const { return position_; }
  
  #ifdef DEBUG
    void Print();
    void Print(Isolate* isolate);
  #endif  // DEBUG
  
    // Type testing & conversion functions overridden by concrete subclasses.
  #define DECLARE_NODE_FUNCTIONS(type) \
    V8_INLINE bool Is##type() const;   \
    V8_INLINE type* As##type();        \
    V8_INLINE const type* As##type() const;
    AST_NODE_LIST(DECLARE_NODE_FUNCTIONS)
    FAILURE_NODE_LIST(DECLARE_NODE_FUNCTIONS)
  #undef DECLARE_NODE_FUNCTIONS
  
    IterationStatement* AsIterationStatement();
    MaterializedLiteral* AsMaterializedLiteral();
  
   private:
    // Hidden to prevent accidental usage. It would have to load the
    // current zone from the TLS.
    void* operator new(size_t size);
  
    int position_;
    class NodeTypeField : public BitField<NodeType, 0, 6> {};
  
   protected:
    uint32_t bit_field_;
    static const uint8_t kNextBitFieldIndex = NodeTypeField::kNext;
  
    AstNode(int position, NodeType type)
        : position_(position), bit_field_(NodeTypeField::encode(type)) {}
  };
  
  
  class Statement : public AstNode {
   public:
    bool IsJump() const;
  
   protected:
    Statement(int position, NodeType type) : AstNode(position, type) {}
  
    static const uint8_t kNextBitFieldIndex = AstNode::kNextBitFieldIndex;
  };
  
  
  class Expression : public AstNode {
   public:
    enum Context {
      // Not assigned a context yet, or else will not be visited during
      // code generation.
      kUninitialized,
      // Evaluated for its side effects.
      kEffect,
      // Evaluated for its value (and side effects).
      kValue,
      // Evaluated for control flow (and side effects).
      kTest
    };
  
    // True iff the expression is a valid reference expression.
    bool IsValidReferenceExpression() const;
  
    // Helpers for ToBoolean conversion.
    bool ToBooleanIsTrue() const;
    bool ToBooleanIsFalse() const;
  
    // Symbols that cannot be parsed as array indices are considered property
    // names.  We do not treat symbols that can be array indexes as property
    // names because [] for string objects is handled only by keyed ICs.
    bool IsPropertyName() const;
  
    // True iff the expression is a class or function expression without
    // a syntactic name.
    bool IsAnonymousFunctionDefinition() const;
  
    // True iff the expression is a concise method definition.
    bool IsConciseMethodDefinition() const;
  
    // True iff the expression is an accessor function definition.
    bool IsAccessorFunctionDefinition() const;
  
    // True iff the expression is a literal represented as a smi.
    bool IsSmiLiteral() const;
  
    // True iff the expression is a literal represented as a number.
    bool IsNumberLiteral() const;
  
    // True iff the expression is a string literal.
    bool IsStringLiteral() const;
  
    // True iff the expression is the null literal.
    bool IsNullLiteral() const;
  
    // True iff the expression is the hole literal.
    bool IsTheHoleLiteral() const;
  
    // True if we can prove that the expression is the undefined literal. Note
    // that this also checks for loads of the global "undefined" variable.
    bool IsUndefinedLiteral() const;
  
    bool IsCompileTimeValue();
  
    bool IsPattern() {
      STATIC_ASSERT(kObjectLiteral + 1 == kArrayLiteral);
      return IsInRange(node_type(), kObjectLiteral, kArrayLiteral);
    }
  
    bool is_parenthesized() const {
      return IsParenthesizedField::decode(bit_field_);
    }
  
    void mark_parenthesized() {
      bit_field_ = IsParenthesizedField::update(bit_field_, true);
    }
  
    void clear_parenthesized() {
      bit_field_ = IsParenthesizedField::update(bit_field_, false);
    }
  
   private:
    class IsParenthesizedField
        : public BitField<bool, AstNode::kNextBitFieldIndex, 1> {};
  
   protected:
    Expression(int pos, NodeType type) : AstNode(pos, type) {
      DCHECK(!is_parenthesized());
    }
  
    static const uint8_t kNextBitFieldIndex = IsParenthesizedField::kNext;
  };
  
  class FailureExpression : public Expression {
   private:
    friend class AstNodeFactory;
    FailureExpression() : Expression(kNoSourcePosition, kFailureExpression) {}
  };
  
  // V8's notion of BreakableStatement does not correspond to the notion of
  // BreakableStatement in ECMAScript. In V8, the idea is that a
  // BreakableStatement is a statement that can be the target of a break
  // statement.  The BreakableStatement AST node carries a list of labels, any of
  // which can be used as an argument to the break statement in order to target
  // it.
  //
  // Since we don't want to attach a list of labels to all kinds of statements, we
  // only declare switchs, loops, and blocks as BreakableStatements.  This means
  // that we implement breaks targeting other statement forms as breaks targeting
  // a substatement thereof. For instance, in "foo: if (b) { f(); break foo; }" we
  // pretend that foo is the label of the inner block. That's okay because one
  // can't observe the difference.
  //
  // This optimization makes it harder to detect invalid continue labels, see the
  // need for own_labels in IterationStatement.
  //
  class BreakableStatement : public Statement {
   public:
    enum BreakableType {
      TARGET_FOR_ANONYMOUS,
      TARGET_FOR_NAMED_ONLY
    };
  
    // A list of all labels declared on the path up to the previous
    // BreakableStatement (if any).
    //
    // Example: "l1: for (;;) l2: l3: { l4: if (b) l5: { s } }"
    // labels() of the ForStatement will be l1.
    // labels() of the Block { l4: ... } will be l2, l3.
    // labels() of the Block { s } will be l4, l5.
    ZonePtrList<const AstRawString>* labels() const;
  
    // Testers.
    bool is_target_for_anonymous() const {
      return BreakableTypeField::decode(bit_field_) == TARGET_FOR_ANONYMOUS;
    }
  
   private:
    class BreakableTypeField
        : public BitField<BreakableType, Statement::kNextBitFieldIndex, 1> {};
  
   protected:
    BreakableStatement(BreakableType breakable_type, int position, NodeType type)
        : Statement(position, type) {
      bit_field_ |= BreakableTypeField::encode(breakable_type);
    }
  
    static const uint8_t kNextBitFieldIndex = BreakableTypeField::kNext;
  };
  
  class Block : public BreakableStatement {
   public:
    ZonePtrList<Statement>* statements() { return &statements_; }
    bool ignore_completion_value() const {
      return IgnoreCompletionField::decode(bit_field_);
    }
  
    inline ZonePtrList<const AstRawString>* labels() const;
  
    bool IsJump() const {
      return !statements_.is_empty() && statements_.last()->IsJump() &&
             labels() == nullptr;  // Good enough as an approximation...
    }
  
    Scope* scope() const { return scope_; }
    void set_scope(Scope* scope) { scope_ = scope; }
  
    void InitializeStatements(const ScopedPtrList<Statement>& statements,
                              Zone* zone) {
      DCHECK_EQ(0, statements_.length());
      statements.CopyTo(&statements_, zone);
    }
  
   private:
    friend class AstNodeFactory;
  
    ZonePtrList<Statement> statements_;
    Scope* scope_;
  
    class IgnoreCompletionField
        : public BitField<bool, BreakableStatement::kNextBitFieldIndex, 1> {};
    class IsLabeledField
        : public BitField<bool, IgnoreCompletionField::kNext, 1> {};
  
   protected:
    Block(Zone* zone, ZonePtrList<const AstRawString>* labels, int capacity,
          bool ignore_completion_value)
        : BreakableStatement(TARGET_FOR_NAMED_ONLY, kNoSourcePosition, kBlock),
          statements_(capacity, zone),
          scope_(nullptr) {
      bit_field_ |= IgnoreCompletionField::encode(ignore_completion_value) |
                    IsLabeledField::encode(labels != nullptr);
    }
  
    Block(ZonePtrList<const AstRawString>* labels, bool ignore_completion_value)
        : Block(nullptr, labels, 0, ignore_completion_value) {}
  };
  
  class LabeledBlock final : public Block {
   private:
    friend class AstNodeFactory;
    friend class Block;
  
    LabeledBlock(Zone* zone, ZonePtrList<const AstRawString>* labels,
                 int capacity, bool ignore_completion_value)
        : Block(zone, labels, capacity, ignore_completion_value),
          labels_(labels) {
      DCHECK_NOT_NULL(labels);
      DCHECK_GT(labels->length(), 0);
    }
  
    LabeledBlock(ZonePtrList<const AstRawString>* labels,
                 bool ignore_completion_value)
        : LabeledBlock(nullptr, labels, 0, ignore_completion_value) {}
  
    ZonePtrList<const AstRawString>* labels_;
  };
  
  inline ZonePtrList<const AstRawString>* Block::labels() const {
    if (IsLabeledField::decode(bit_field_)) {
      return static_cast<const LabeledBlock*>(this)->labels_;
    }
    return nullptr;
  }
  
  class DoExpression final : public Expression {
   public:
    Block* block() { return block_; }
    VariableProxy* result() { return result_; }
  
   private:
    friend class AstNodeFactory;
  
    DoExpression(Block* block, VariableProxy* result, int pos)
        : Expression(pos, kDoExpression), block_(block), result_(result) {
      DCHECK_NOT_NULL(block_);
      DCHECK_NOT_NULL(result_);
    }
  
    Block* block_;
    VariableProxy* result_;
  };
  
  
  class Declaration : public AstNode {
   public:
    typedef base::ThreadedList<Declaration> List;
  
    Variable* var() const { return var_; }
    void set_var(Variable* var) { var_ = var; }
  
   protected:
    Declaration(int pos, NodeType type) : AstNode(pos, type), next_(nullptr) {}
  
   private:
    Variable* var_;
    // Declarations list threaded through the declarations.
    Declaration** next() { return &next_; }
    Declaration* next_;
    friend List;
    friend base::ThreadedListTraits<Declaration>;
  };
  
  class VariableDeclaration : public Declaration {
   public:
    inline NestedVariableDeclaration* AsNested();
  
   private:
    friend class AstNodeFactory;
  
    class IsNestedField
        : public BitField<bool, Declaration::kNextBitFieldIndex, 1> {};
  
   protected:
    explicit VariableDeclaration(int pos, bool is_nested = false)
        : Declaration(pos, kVariableDeclaration) {
      bit_field_ = IsNestedField::update(bit_field_, is_nested);
    }
  
    static const uint8_t kNextBitFieldIndex = IsNestedField::kNext;
  };
  
  // For var declarations that appear in a block scope.
  // Only distinguished from VariableDeclaration during Scope analysis,
  // so it doesn't get its own NodeType.
  class NestedVariableDeclaration final : public VariableDeclaration {
   public:
    Scope* scope() const { return scope_; }
  
   private:
    friend class AstNodeFactory;
  
    NestedVariableDeclaration(Scope* scope, int pos)
        : VariableDeclaration(pos, true), scope_(scope) {}
  
    // Nested scope from which the declaration originated.
    Scope* scope_;
  };
  
  inline NestedVariableDeclaration* VariableDeclaration::AsNested() {
    return IsNestedField::decode(bit_field_)
               ? static_cast<NestedVariableDeclaration*>(this)
               : nullptr;
  }
  
  class FunctionDeclaration final : public Declaration {
   public:
    FunctionLiteral* fun() const { return fun_; }
  
   private:
    friend class AstNodeFactory;
  
    FunctionDeclaration(FunctionLiteral* fun, int pos)
        : Declaration(pos, kFunctionDeclaration), fun_(fun) {}
  
    FunctionLiteral* fun_;
  };
  
  
  class IterationStatement : public BreakableStatement {
   public:
    Statement* body() const { return body_; }
    void set_body(Statement* s) { body_ = s; }
  
    ZonePtrList<const AstRawString>* labels() const { return labels_; }
  
    // A list of all labels that the iteration statement is directly prefixed
    // with, i.e.  all the labels that a continue statement in the body can use to
    // continue this iteration statement. This is always a subset of {labels}.
    //
    // Example: "l1: { l2: if (b) l3: l4: for (;;) s }"
    // labels() of the Block will be l1.
    // labels() of the ForStatement will be l2, l3, l4.
    // own_labels() of the ForStatement will be l3, l4.
    ZonePtrList<const AstRawString>* own_labels() const { return own_labels_; }
  
   protected:
    IterationStatement(ZonePtrList<const AstRawString>* labels,
                       ZonePtrList<const AstRawString>* own_labels, int pos,
                       NodeType type)
        : BreakableStatement(TARGET_FOR_ANONYMOUS, pos, type),
          labels_(labels),
          own_labels_(own_labels),
          body_(nullptr) {}
    void Initialize(Statement* body) { body_ = body; }
  
    static const uint8_t kNextBitFieldIndex =
        BreakableStatement::kNextBitFieldIndex;
  
   private:
    ZonePtrList<const AstRawString>* labels_;
    ZonePtrList<const AstRawString>* own_labels_;
    Statement* body_;
  };
  
  
  class DoWhileStatement final : public IterationStatement {
   public:
    void Initialize(Expression* cond, Statement* body) {
      IterationStatement::Initialize(body);
      cond_ = cond;
    }
  
    Expression* cond() const { return cond_; }
  
   private:
    friend class AstNodeFactory;
  
    DoWhileStatement(ZonePtrList<const AstRawString>* labels,
                     ZonePtrList<const AstRawString>* own_labels, int pos)
        : IterationStatement(labels, own_labels, pos, kDoWhileStatement),
          cond_(nullptr) {}
  
    Expression* cond_;
  };
  
  
  class WhileStatement final : public IterationStatement {
   public:
    void Initialize(Expression* cond, Statement* body) {
      IterationStatement::Initialize(body);
      cond_ = cond;
    }
  
    Expression* cond() const { return cond_; }
  
   private:
    friend class AstNodeFactory;
  
    WhileStatement(ZonePtrList<const AstRawString>* labels,
                   ZonePtrList<const AstRawString>* own_labels, int pos)
        : IterationStatement(labels, own_labels, pos, kWhileStatement),
          cond_(nullptr) {}
  
    Expression* cond_;
  };
  
  
  class ForStatement final : public IterationStatement {
   public:
    void Initialize(Statement* init, Expression* cond, Statement* next,
                    Statement* body) {
      IterationStatement::Initialize(body);
      init_ = init;
      cond_ = cond;
      next_ = next;
    }
  
    Statement* init() const { return init_; }
    Expression* cond() const { return cond_; }
    Statement* next() const { return next_; }
  
   private:
    friend class AstNodeFactory;
  
    ForStatement(ZonePtrList<const AstRawString>* labels,
                 ZonePtrList<const AstRawString>* own_labels, int pos)
        : IterationStatement(labels, own_labels, pos, kForStatement),
          init_(nullptr),
          cond_(nullptr),
          next_(nullptr) {}
  
    Statement* init_;
    Expression* cond_;
    Statement* next_;
  };
  
  // Shared class for for-in and for-of statements.
  class ForEachStatement : public IterationStatement {
   public:
    enum VisitMode {
      ENUMERATE,   // for (each in subject) body;
      ITERATE      // for (each of subject) body;
    };
  
    using IterationStatement::Initialize;
  
    static const char* VisitModeString(VisitMode mode) {
      return mode == ITERATE ? "for-of" : "for-in";
    }
  
    void Initialize(Expression* each, Expression* subject, Statement* body) {
      IterationStatement::Initialize(body);
      each_ = each;
      subject_ = subject;
    }
  
    Expression* each() const { return each_; }
    Expression* subject() const { return subject_; }
  
   protected:
    friend class AstNodeFactory;
  
    ForEachStatement(ZonePtrList<const AstRawString>* labels,
                     ZonePtrList<const AstRawString>* own_labels, int pos,
                     NodeType type)
        : IterationStatement(labels, own_labels, pos, type),
          each_(nullptr),
          subject_(nullptr) {}
  
    Expression* each_;
    Expression* subject_;
  };
  
  class ForInStatement final : public ForEachStatement {
   private:
    friend class AstNodeFactory;
  
    ForInStatement(ZonePtrList<const AstRawString>* labels,
                   ZonePtrList<const AstRawString>* own_labels, int pos)
        : ForEachStatement(labels, own_labels, pos, kForInStatement) {}
  };
  
  enum class IteratorType { kNormal, kAsync };
  class ForOfStatement final : public ForEachStatement {
   public:
    IteratorType type() const { return type_; }
  
   private:
    friend class AstNodeFactory;
  
    ForOfStatement(ZonePtrList<const AstRawString>* labels,
                   ZonePtrList<const AstRawString>* own_labels, int pos,
                   IteratorType type)
        : ForEachStatement(labels, own_labels, pos, kForOfStatement),
          type_(type) {}
  
    IteratorType type_;
  };
  
  class ExpressionStatement final : public Statement {
   public:
    void set_expression(Expression* e) { expression_ = e; }
    Expression* expression() const { return expression_; }
    bool IsJump() const { return expression_->IsThrow(); }
  
   private:
    friend class AstNodeFactory;
  
    ExpressionStatement(Expression* expression, int pos)
        : Statement(pos, kExpressionStatement), expression_(expression) {}
  
    Expression* expression_;
  };
  
  
  class JumpStatement : public Statement {
   public:
    bool IsJump() const { return true; }
  
   protected:
    JumpStatement(int pos, NodeType type) : Statement(pos, type) {}
  };
  
  
  class ContinueStatement final : public JumpStatement {
   public:
    IterationStatement* target() const { return target_; }
  
   private:
    friend class AstNodeFactory;
  
    ContinueStatement(IterationStatement* target, int pos)
        : JumpStatement(pos, kContinueStatement), target_(target) {}
  
    IterationStatement* target_;
  };
  
  
  class BreakStatement final : public JumpStatement {
   public:
    BreakableStatement* target() const { return target_; }
  
   private:
    friend class AstNodeFactory;
  
    BreakStatement(BreakableStatement* target, int pos)
        : JumpStatement(pos, kBreakStatement), target_(target) {}
  
    BreakableStatement* target_;
  };
  
  
  class ReturnStatement final : public JumpStatement {
   public:
    enum Type { kNormal, kAsyncReturn };
    Expression* expression() const { return expression_; }
  
    Type type() const { return TypeField::decode(bit_field_); }
    bool is_async_return() const { return type() == kAsyncReturn; }
  
    int end_position() const { return end_position_; }
  
   private:
    friend class AstNodeFactory;
  
    ReturnStatement(Expression* expression, Type type, int pos, int end_position)
        : JumpStatement(pos, kReturnStatement),
          expression_(expression),
          end_position_(end_position) {
      bit_field_ |= TypeField::encode(type);
    }
  
    Expression* expression_;
    int end_position_;
  
    class TypeField
        : public BitField<Type, JumpStatement::kNextBitFieldIndex, 1> {};
  };
  
  
  class WithStatement final : public Statement {
   public:
    Scope* scope() { return scope_; }
    Expression* expression() const { return expression_; }
    Statement* statement() const { return statement_; }
    void set_statement(Statement* s) { statement_ = s; }
  
   private:
    friend class AstNodeFactory;
  
    WithStatement(Scope* scope, Expression* expression, Statement* statement,
                  int pos)
        : Statement(pos, kWithStatement),
          scope_(scope),
          expression_(expression),
          statement_(statement) {}
  
    Scope* scope_;
    Expression* expression_;
    Statement* statement_;
  };
  
  class CaseClause final : public ZoneObject {
   public:
    bool is_default() const { return label_ == nullptr; }
    Expression* label() const {
      DCHECK(!is_default());
      return label_;
    }
    ZonePtrList<Statement>* statements() { return &statements_; }
  
   private:
    friend class AstNodeFactory;
  
    CaseClause(Zone* zone, Expression* label,
               const ScopedPtrList<Statement>& statements);
  
    Expression* label_;
    ZonePtrList<Statement> statements_;
  };
  
  
  class SwitchStatement final : public BreakableStatement {
   public:
    ZonePtrList<const AstRawString>* labels() const { return labels_; }
  
    Expression* tag() const { return tag_; }
    void set_tag(Expression* t) { tag_ = t; }
  
    ZonePtrList<CaseClause>* cases() { return &cases_; }
  
   private:
    friend class AstNodeFactory;
  
    SwitchStatement(Zone* zone, ZonePtrList<const AstRawString>* labels,
                    Expression* tag, int pos)
        : BreakableStatement(TARGET_FOR_ANONYMOUS, pos, kSwitchStatement),
          labels_(labels),
          tag_(tag),
          cases_(4, zone) {}
  
    ZonePtrList<const AstRawString>* labels_;
    Expression* tag_;
    ZonePtrList<CaseClause> cases_;
  };
  
  
  // If-statements always have non-null references to their then- and
  // else-parts. When parsing if-statements with no explicit else-part,
  // the parser implicitly creates an empty statement. Use the
  // HasThenStatement() and HasElseStatement() functions to check if a
  // given if-statement has a then- or an else-part containing code.
  class IfStatement final : public Statement {
   public:
    bool HasThenStatement() const { return !then_statement_->IsEmptyStatement(); }
    bool HasElseStatement() const { return !else_statement_->IsEmptyStatement(); }
  
    Expression* condition() const { return condition_; }
    Statement* then_statement() const { return then_statement_; }
    Statement* else_statement() const { return else_statement_; }
  
    void set_then_statement(Statement* s) { then_statement_ = s; }
    void set_else_statement(Statement* s) { else_statement_ = s; }
  
    bool IsJump() const {
      return HasThenStatement() && then_statement()->IsJump()
          && HasElseStatement() && else_statement()->IsJump();
    }
  
   private:
    friend class AstNodeFactory;
  
    IfStatement(Expression* condition, Statement* then_statement,
                Statement* else_statement, int pos)
        : Statement(pos, kIfStatement),
          condition_(condition),
          then_statement_(then_statement),
          else_statement_(else_statement) {}
  
    Expression* condition_;
    Statement* then_statement_;
    Statement* else_statement_;
  };
  
  
  class TryStatement : public Statement {
   public:
    Block* try_block() const { return try_block_; }
    void set_try_block(Block* b) { try_block_ = b; }
  
   protected:
    TryStatement(Block* try_block, int pos, NodeType type)
        : Statement(pos, type), try_block_(try_block) {}
  
   private:
    Block* try_block_;
  };
  
  
  class TryCatchStatement final : public TryStatement {
   public:
    Scope* scope() { return scope_; }
    Block* catch_block() const { return catch_block_; }
    void set_catch_block(Block* b) { catch_block_ = b; }
  
    // Prediction of whether exceptions thrown into the handler for this try block
    // will be caught.
    //
    // BytecodeGenerator tracks the state of catch prediction, which can change
    // with each TryCatchStatement encountered. The tracked catch prediction is
    // later compiled into the code's handler table. The runtime uses this
    // information to implement a feature that notifies the debugger when an
    // uncaught exception is thrown, _before_ the exception propagates to the top.
    //
    // If this try/catch statement is meant to rethrow (HandlerTable::UNCAUGHT),
    // the catch prediction value is set to the same value as the surrounding
    // catch prediction.
    //
    // Since it's generally undecidable whether an exception will be caught, our
    // prediction is only an approximation.
    // ---------------------------------------------------------------------------
    inline HandlerTable::CatchPrediction GetCatchPrediction(
        HandlerTable::CatchPrediction outer_catch_prediction) const {
      if (catch_prediction_ == HandlerTable::UNCAUGHT) {
        return outer_catch_prediction;
      }
      return catch_prediction_;
    }
  
    // Indicates whether or not code should be generated to clear the pending
    // exception. The pending exception is cleared for cases where the exception
    // is not guaranteed to be rethrown, indicated by the value
    // HandlerTable::UNCAUGHT. If both the current and surrounding catch handler's
    // are predicted uncaught, the exception is not cleared.
    //
    // If this handler is not going to simply rethrow the exception, this method
    // indicates that the isolate's pending exception message should be cleared
    // before executing the catch_block.
    // In the normal use case, this flag is always on because the message object
    // is not needed anymore when entering the catch block and should not be
    // kept alive.
    // The use case where the flag is off is when the catch block is guaranteed
    // to rethrow the caught exception (using %ReThrow), which reuses the
    // pending message instead of generating a new one.
    // (When the catch block doesn't rethrow but is guaranteed to perform an
    // ordinary throw, not clearing the old message is safe but not very
    // useful.)
    inline bool ShouldClearPendingException(
        HandlerTable::CatchPrediction outer_catch_prediction) const {
      return catch_prediction_ != HandlerTable::UNCAUGHT ||
             outer_catch_prediction != HandlerTable::UNCAUGHT;
    }
  
   private:
    friend class AstNodeFactory;
  
    TryCatchStatement(Block* try_block, Scope* scope, Block* catch_block,
                      HandlerTable::CatchPrediction catch_prediction, int pos)
        : TryStatement(try_block, pos, kTryCatchStatement),
          scope_(scope),
          catch_block_(catch_block),
          catch_prediction_(catch_prediction) {}
  
    Scope* scope_;
    Block* catch_block_;
    HandlerTable::CatchPrediction catch_prediction_;
  };
  
  
  class TryFinallyStatement final : public TryStatement {
   public:
    Block* finally_block() const { return finally_block_; }
    void set_finally_block(Block* b) { finally_block_ = b; }
  
   private:
    friend class AstNodeFactory;
  
    TryFinallyStatement(Block* try_block, Block* finally_block, int pos)
        : TryStatement(try_block, pos, kTryFinallyStatement),
          finally_block_(finally_block) {}
  
    Block* finally_block_;
  };
  
  
  class DebuggerStatement final : public Statement {
   private:
    friend class AstNodeFactory;
  
    explicit DebuggerStatement(int pos) : Statement(pos, kDebuggerStatement) {}
  };
  
  
  class EmptyStatement final : public Statement {
   private:
    friend class AstNodeFactory;
    EmptyStatement() : Statement(kNoSourcePosition, kEmptyStatement) {}
  };
  
  
  // Delegates to another statement, which may be overwritten.
  // This was introduced to implement ES2015 Annex B3.3 for conditionally making
  // sloppy-mode block-scoped functions have a var binding, which is changed
  // from one statement to another during parsing.
  class SloppyBlockFunctionStatement final : public Statement {
   public:
    Statement* statement() const { return statement_; }
    void set_statement(Statement* statement) { statement_ = statement; }
    Scope* scope() const { return var_->scope(); }
    Variable* var() const { return var_; }
    Token::Value init() const { return TokenField::decode(bit_field_); }
    const AstRawString* name() const { return var_->raw_name(); }
    SloppyBlockFunctionStatement** next() { return &next_; }
  
   private:
    friend class AstNodeFactory;
  
    class TokenField
        : public BitField<Token::Value, Statement::kNextBitFieldIndex, 8> {};
  
    SloppyBlockFunctionStatement(int pos, Variable* var, Token::Value init,
                                 Statement* statement)
        : Statement(pos, kSloppyBlockFunctionStatement),
          var_(var),
          statement_(statement),
          next_(nullptr) {
      bit_field_ = TokenField::update(bit_field_, init);
    }
  
    Variable* var_;
    Statement* statement_;
    SloppyBlockFunctionStatement* next_;
  };
  
  
  class Literal final : public Expression {
   public:
    enum Type {
      kSmi,
      kHeapNumber,
      kBigInt,
      kString,
      kSymbol,
      kBoolean,
      kUndefined,
      kNull,
      kTheHole,
    };
  
    Type type() const { return TypeField::decode(bit_field_); }
  
    // Returns true if literal represents a property name (i.e. cannot be parsed
    // as array indices).
    bool IsPropertyName() const;
  
    // Returns true if literal represents an array index.
    // Note, that in general the following statement is not true:
    //   key->IsPropertyName() != key->AsArrayIndex(...)
    // but for non-computed LiteralProperty properties the following is true:
    //   property->key()->IsPropertyName() != property->key()->AsArrayIndex(...)
    bool AsArrayIndex(uint32_t* index) const;
  
    const AstRawString* AsRawPropertyName() {
      DCHECK(IsPropertyName());
      return string_;
    }
  
    Smi AsSmiLiteral() const {
      DCHECK_EQ(kSmi, type());
      return Smi::FromInt(smi_);
    }
  
    // Returns true if literal represents a Number.
    bool IsNumber() const { return type() == kHeapNumber || type() == kSmi; }
    double AsNumber() const {
      DCHECK(IsNumber());
      switch (type()) {
        case kSmi:
          return smi_;
        case kHeapNumber:
          return number_;
        default:
          UNREACHABLE();
      }
    }
  
    AstBigInt AsBigInt() const {
      DCHECK_EQ(type(), kBigInt);
      return bigint_;
    }
  
    bool IsString() const { return type() == kString; }
    const AstRawString* AsRawString() {
      DCHECK_EQ(type(), kString);
      return string_;
    }
  
    AstSymbol AsSymbol() {
      DCHECK_EQ(type(), kSymbol);
      return symbol_;
    }
  
    V8_EXPORT_PRIVATE bool ToBooleanIsTrue() const;
    bool ToBooleanIsFalse() const { return !ToBooleanIsTrue(); }
  
    bool ToUint32(uint32_t* value) const;
  
    // Returns an appropriate Object representing this Literal, allocating
    // a heap object if needed.
    Handle<Object> BuildValue(Isolate* isolate) const;
  
    // Support for using Literal as a HashMap key. NOTE: Currently, this works
    // only for string and number literals!
    uint32_t Hash();
    static bool Match(void* literal1, void* literal2);
  
   private:
    friend class AstNodeFactory;
  
    class TypeField : public BitField<Type, Expression::kNextBitFieldIndex, 4> {};
  
    Literal(int smi, int position) : Expression(position, kLiteral), smi_(smi) {
      bit_field_ = TypeField::update(bit_field_, kSmi);
    }
  
    Literal(double number, int position)
        : Expression(position, kLiteral), number_(number) {
      bit_field_ = TypeField::update(bit_field_, kHeapNumber);
    }
  
    Literal(AstBigInt bigint, int position)
        : Expression(position, kLiteral), bigint_(bigint) {
      bit_field_ = TypeField::update(bit_field_, kBigInt);
    }
  
    Literal(const AstRawString* string, int position)
        : Expression(position, kLiteral), string_(string) {
      bit_field_ = TypeField::update(bit_field_, kString);
    }
  
    Literal(AstSymbol symbol, int position)
        : Expression(position, kLiteral), symbol_(symbol) {
      bit_field_ = TypeField::update(bit_field_, kSymbol);
    }
  
    Literal(bool boolean, int position)
        : Expression(position, kLiteral), boolean_(boolean) {
      bit_field_ = TypeField::update(bit_field_, kBoolean);
    }
  
    Literal(Type type, int position) : Expression(position, kLiteral) {
      DCHECK(type == kNull || type == kUndefined || type == kTheHole);
      bit_field_ = TypeField::update(bit_field_, type);
    }
  
    union {
      const AstRawString* string_;
      int smi_;
      double number_;
      AstSymbol symbol_;
      AstBigInt bigint_;
      bool boolean_;
    };
  };
  
  // Base class for literals that need space in the type feedback vector.
  class MaterializedLiteral : public Expression {
   public:
    // A Materializedliteral is simple if the values consist of only
    // constants and simple object and array literals.
    bool IsSimple() const;
  
   protected:
    MaterializedLiteral(int pos, NodeType type) : Expression(pos, type) {}
  
    friend class CompileTimeValue;
    friend class ArrayLiteral;
    friend class ObjectLiteral;
  
    // Populate the depth field and any flags the literal has, returns the depth.
    int InitDepthAndFlags();
  
    bool NeedsInitialAllocationSite();
  
    // Populate the constant properties/elements fixed array.
    void BuildConstants(Isolate* isolate);
  
    // If the expression is a literal, return the literal value;
    // if the expression is a materialized literal and is_simple
    // then return an Array or Object Boilerplate Description
    // Otherwise, return undefined literal as the placeholder
    // in the object literal boilerplate.
    Handle<Object> GetBoilerplateValue(Expression* expression, Isolate* isolate);
  };
  
  // Node for capturing a regexp literal.
  class RegExpLiteral final : public MaterializedLiteral {
   public:
    Handle<String> pattern() const { return pattern_->string(); }
    const AstRawString* raw_pattern() const { return pattern_; }
    int flags() const { return flags_; }
  
   private:
    friend class AstNodeFactory;
  
    RegExpLiteral(const AstRawString* pattern, int flags, int pos)
        : MaterializedLiteral(pos, kRegExpLiteral),
          flags_(flags),
          pattern_(pattern) {}
  
    int const flags_;
    const AstRawString* const pattern_;
  };
  
  // Base class for Array and Object literals, providing common code for handling
  // nested subliterals.
  class AggregateLiteral : public MaterializedLiteral {
   public:
    enum Flags {
      kNoFlags = 0,
      kIsShallow = 1,
      kDisableMementos = 1 << 1,
      kNeedsInitialAllocationSite = 1 << 2,
    };
  
    bool is_initialized() const { return 0 < depth_; }
    int depth() const {
      DCHECK(is_initialized());
      return depth_;
    }
  
    bool is_shallow() const { return depth() == 1; }
    bool needs_initial_allocation_site() const {
      return NeedsInitialAllocationSiteField::decode(bit_field_);
    }
  
    int ComputeFlags(bool disable_mementos = false) const {
      int flags = kNoFlags;
      if (is_shallow()) flags |= kIsShallow;
      if (disable_mementos) flags |= kDisableMementos;
      if (needs_initial_allocation_site()) flags |= kNeedsInitialAllocationSite;
      return flags;
    }
  
    // An AggregateLiteral is simple if the values consist of only
    // constants and simple object and array literals.
    bool is_simple() const { return IsSimpleField::decode(bit_field_); }
  
   private:
    int depth_ : 31;
    class NeedsInitialAllocationSiteField
        : public BitField<bool, MaterializedLiteral::kNextBitFieldIndex, 1> {};
    class IsSimpleField
        : public BitField<bool, NeedsInitialAllocationSiteField::kNext, 1> {};
  
   protected:
    friend class AstNodeFactory;
    AggregateLiteral(int pos, NodeType type)
        : MaterializedLiteral(pos, type), depth_(0) {
      bit_field_ |= NeedsInitialAllocationSiteField::encode(false) |
                    IsSimpleField::encode(false);
    }
  
    void set_is_simple(bool is_simple) {
      bit_field_ = IsSimpleField::update(bit_field_, is_simple);
    }
  
    void set_depth(int depth) {
      DCHECK(!is_initialized());
      depth_ = depth;
    }
  
    void set_needs_initial_allocation_site(bool required) {
      bit_field_ = NeedsInitialAllocationSiteField::update(bit_field_, required);
    }
  
    static const uint8_t kNextBitFieldIndex = IsSimpleField::kNext;
  };
  
  // Common supertype for ObjectLiteralProperty and ClassLiteralProperty
  class LiteralProperty : public ZoneObject {
   public:
    Expression* key() const { return key_and_is_computed_name_.GetPointer(); }
    Expression* value() const { return value_; }
  
    bool is_computed_name() const {
      return key_and_is_computed_name_.GetPayload();
    }
    bool NeedsSetFunctionName() const;
  
   protected:
    LiteralProperty(Expression* key, Expression* value, bool is_computed_name)
        : key_and_is_computed_name_(key, is_computed_name), value_(value) {}
  
    PointerWithPayload<Expression, bool, 1> key_and_is_computed_name_;
    Expression* value_;
  };
  
  // Property is used for passing information
  // about an object literal's properties from the parser
  // to the code generator.
  class ObjectLiteralProperty final : public LiteralProperty {
   public:
    enum Kind : uint8_t {
      CONSTANT,              // Property with constant value (compile time).
      COMPUTED,              // Property with computed value (execution time).
      MATERIALIZED_LITERAL,  // Property value is a materialized literal.
      GETTER,
      SETTER,     // Property is an accessor function.
      PROTOTYPE,  // Property is __proto__.
      SPREAD
    };
  
    Kind kind() const { return kind_; }
  
    bool IsCompileTimeValue() const;
  
    void set_emit_store(bool emit_store);
    bool emit_store() const;
  
    bool IsNullPrototype() const {
      return IsPrototype() && value()->IsNullLiteral();
    }
    bool IsPrototype() const { return kind() == PROTOTYPE; }
  
   private:
    friend class AstNodeFactory;
  
    ObjectLiteralProperty(Expression* key, Expression* value, Kind kind,
                          bool is_computed_name);
    ObjectLiteralProperty(AstValueFactory* ast_value_factory, Expression* key,
                          Expression* value, bool is_computed_name);
  
    Kind kind_;
    bool emit_store_;
  };
  
  
  // An object literal has a boilerplate object that is used
  // for minimizing the work when constructing it at runtime.
  class ObjectLiteral final : public AggregateLiteral {
   public:
    typedef ObjectLiteralProperty Property;
  
    Handle<ObjectBoilerplateDescription> boilerplate_description() const {
      DCHECK(!boilerplate_description_.is_null());
      return boilerplate_description_;
    }
    int properties_count() const { return boilerplate_properties_; }
    const ZonePtrList<Property>* properties() const { return &properties_; }
    bool has_elements() const { return HasElementsField::decode(bit_field_); }
    bool has_rest_property() const {
      return HasRestPropertyField::decode(bit_field_);
    }
    bool fast_elements() const { return FastElementsField::decode(bit_field_); }
    bool has_null_prototype() const {
      return HasNullPrototypeField::decode(bit_field_);
    }
  
    bool is_empty() const {
      DCHECK(is_initialized());
      return !has_elements() && properties_count() == 0 &&
             properties()->length() == 0;
    }
  
    bool IsEmptyObjectLiteral() const {
      return is_empty() && !has_null_prototype();
    }
  
    // Populate the depth field and flags, returns the depth.
    int InitDepthAndFlags();
  
    // Get the boilerplate description, populating it if necessary.
    Handle<ObjectBoilerplateDescription> GetOrBuildBoilerplateDescription(
        Isolate* isolate) {
      if (boilerplate_description_.is_null()) {
        BuildBoilerplateDescription(isolate);
      }
      return boilerplate_description();
    }
  
    // Populate the boilerplate description.
    void BuildBoilerplateDescription(Isolate* isolate);
  
    // Mark all computed expressions that are bound to a key that
    // is shadowed by a later occurrence of the same key. For the
    // marked expressions, no store code is emitted.
    void CalculateEmitStore(Zone* zone);
  
    // Determines whether the {CreateShallowObjectLiteratal} builtin can be used.
    bool IsFastCloningSupported() const;
  
    // Assemble bitfield of flags for the CreateObjectLiteral helper.
    int ComputeFlags(bool disable_mementos = false) const {
      int flags = AggregateLiteral::ComputeFlags(disable_mementos);
      if (fast_elements()) flags |= kFastElements;
      if (has_null_prototype()) flags |= kHasNullPrototype;
      return flags;
    }
  
    int EncodeLiteralType() {
      int flags = kNoFlags;
      if (fast_elements()) flags |= kFastElements;
      if (has_null_prototype()) flags |= kHasNullPrototype;
      return flags;
    }
  
    enum Flags {
      kFastElements = 1 << 3,
      kHasNullPrototype = 1 << 4,
    };
    STATIC_ASSERT(
        static_cast<int>(AggregateLiteral::kNeedsInitialAllocationSite) <
        static_cast<int>(kFastElements));
  
    struct Accessors: public ZoneObject {
      Accessors() : getter(nullptr), setter(nullptr) {}
      ObjectLiteralProperty* getter;
      ObjectLiteralProperty* setter;
    };
  
   private:
    friend class AstNodeFactory;
  
    ObjectLiteral(Zone* zone, const ScopedPtrList<Property>& properties,
                  uint32_t boilerplate_properties, int pos,
                  bool has_rest_property)
        : AggregateLiteral(pos, kObjectLiteral),
          boilerplate_properties_(boilerplate_properties),
          properties_(0, nullptr) {
      bit_field_ |= HasElementsField::encode(false) |
                    HasRestPropertyField::encode(has_rest_property) |
                    FastElementsField::encode(false) |
                    HasNullPrototypeField::encode(false);
      properties.CopyTo(&properties_, zone);
    }
  
    void InitFlagsForPendingNullPrototype(int i);
  
    void set_has_elements(bool has_elements) {
      bit_field_ = HasElementsField::update(bit_field_, has_elements);
    }
    void set_fast_elements(bool fast_elements) {
      bit_field_ = FastElementsField::update(bit_field_, fast_elements);
    }
    void set_has_null_protoype(bool has_null_prototype) {
      bit_field_ = HasNullPrototypeField::update(bit_field_, has_null_prototype);
    }
  
    uint32_t boilerplate_properties_;
    Handle<ObjectBoilerplateDescription> boilerplate_description_;
    ZoneList<Property*> properties_;
  
    class HasElementsField
        : public BitField<bool, AggregateLiteral::kNextBitFieldIndex, 1> {};
    class HasRestPropertyField
        : public BitField<bool, HasElementsField::kNext, 1> {};
    class FastElementsField
        : public BitField<bool, HasRestPropertyField::kNext, 1> {};
    class HasNullPrototypeField
        : public BitField<bool, FastElementsField::kNext, 1> {};
  };
  
  
  // A map from property names to getter/setter pairs allocated in the zone.
  class AccessorTable
      : public base::TemplateHashMap<Literal, ObjectLiteral::Accessors,
                                     bool (*)(void*, void*),
                                     ZoneAllocationPolicy> {
   public:
    explicit AccessorTable(Zone* zone)
        : base::TemplateHashMap<Literal, ObjectLiteral::Accessors,
                                bool (*)(void*, void*), ZoneAllocationPolicy>(
              Literal::Match, ZoneAllocationPolicy(zone)),
          zone_(zone) {}
  
    Iterator lookup(Literal* literal) {
      Iterator it = find(literal, true, ZoneAllocationPolicy(zone_));
      if (it->second == nullptr) {
        it->second = new (zone_) ObjectLiteral::Accessors();
      }
      return it;
    }
  
   private:
    Zone* zone_;
  };
  
  
  // An array literal has a literals object that is used
  // for minimizing the work when constructing it at runtime.
  class ArrayLiteral final : public AggregateLiteral {
   public:
    Handle<ArrayBoilerplateDescription> boilerplate_description() const {
      return boilerplate_description_;
    }
  
    const ZonePtrList<Expression>* values() const { return &values_; }
  
    int first_spread_index() const { return first_spread_index_; }
  
    // Populate the depth field and flags, returns the depth.
    int InitDepthAndFlags();
  
    // Get the boilerplate description, populating it if necessary.
    Handle<ArrayBoilerplateDescription> GetOrBuildBoilerplateDescription(
        Isolate* isolate) {
      if (boilerplate_description_.is_null()) {
        BuildBoilerplateDescription(isolate);
      }
      return boilerplate_description();
    }
  
    // Populate the boilerplate description.
    void BuildBoilerplateDescription(Isolate* isolate);
  
    // Determines whether the {CreateShallowArrayLiteral} builtin can be used.
    bool IsFastCloningSupported() const;
  
    // Assemble bitfield of flags for the CreateArrayLiteral helper.
    int ComputeFlags(bool disable_mementos = false) const {
      return AggregateLiteral::ComputeFlags(disable_mementos);
    }
  
   private:
    friend class AstNodeFactory;
  
    ArrayLiteral(Zone* zone, const ScopedPtrList<Expression>& values,
                 int first_spread_index, int pos)
        : AggregateLiteral(pos, kArrayLiteral),
          first_spread_index_(first_spread_index),
          values_(0, nullptr) {
      values.CopyTo(&values_, zone);
    }
  
    int first_spread_index_;
    Handle<ArrayBoilerplateDescription> boilerplate_description_;
    ZonePtrList<Expression> values_;
  };
  
  enum class HoleCheckMode { kRequired, kElided };
  
  class ThisExpression final : public Expression {
   private:
    friend class AstNodeFactory;
    ThisExpression() : Expression(kNoSourcePosition, kThisExpression) {}
  };
  
  class VariableProxy final : public Expression {
   public:
    bool IsValidReferenceExpression() const { return !is_new_target(); }
  
    Handle<String> name() const { return raw_name()->string(); }
    const AstRawString* raw_name() const {
      return is_resolved() ? var_->raw_name() : raw_name_;
    }
  
    Variable* var() const {
      DCHECK(is_resolved());
      return var_;
    }
    void set_var(Variable* v) {
      DCHECK(!is_resolved());
      DCHECK_NOT_NULL(v);
      var_ = v;
    }
  
    Scanner::Location location() {
      return Scanner::Location(position(), position() + raw_name()->length());
    }
  
    bool is_assigned() const { return IsAssignedField::decode(bit_field_); }
    void set_is_assigned() {
      bit_field_ = IsAssignedField::update(bit_field_, true);
      if (is_resolved()) {
        var()->set_maybe_assigned();
      }
    }
  
    bool is_resolved() const { return IsResolvedField::decode(bit_field_); }
    void set_is_resolved() {
      bit_field_ = IsResolvedField::update(bit_field_, true);
    }
  
    bool is_new_target() const { return IsNewTargetField::decode(bit_field_); }
    void set_is_new_target() {
      bit_field_ = IsNewTargetField::update(bit_field_, true);
    }
  
    HoleCheckMode hole_check_mode() const {
      HoleCheckMode mode = HoleCheckModeField::decode(bit_field_);
      DCHECK_IMPLIES(mode == HoleCheckMode::kRequired,
                     var()->binding_needs_init() ||
                         var()->local_if_not_shadowed()->binding_needs_init());
      return mode;
    }
    void set_needs_hole_check() {
      bit_field_ =
          HoleCheckModeField::update(bit_field_, HoleCheckMode::kRequired);
    }
  
    bool IsPrivateName() const {
      return raw_name()->length() > 0 && raw_name()->FirstCharacter() == '#';
    }
  
    // Bind this proxy to the variable var.
    void BindTo(Variable* var);
  
    V8_INLINE VariableProxy* next_unresolved() { return next_unresolved_; }
    V8_INLINE bool is_removed_from_unresolved() const {
      return IsRemovedFromUnresolvedField::decode(bit_field_);
    }
  
    void mark_removed_from_unresolved() {
      bit_field_ = IsRemovedFromUnresolvedField::update(bit_field_, true);
    }
  
    // Provides filtered access to the unresolved variable proxy threaded list.
    struct UnresolvedNext {
      static VariableProxy** filter(VariableProxy** t) {
        VariableProxy** n = t;
        // Skip over possibly removed values.
        while (*n != nullptr && (*n)->is_removed_from_unresolved()) {
          n = (*n)->next();
        }
        return n;
      }
  
      static VariableProxy** start(VariableProxy** head) { return filter(head); }
  
      static VariableProxy** next(VariableProxy* t) { return filter(t->next()); }
    };
  
   private:
    friend class AstNodeFactory;
  
    VariableProxy(Variable* var, int start_position);
  
    VariableProxy(const AstRawString* name, VariableKind variable_kind,
                  int start_position)
        : Expression(start_position, kVariableProxy),
          raw_name_(name),
          next_unresolved_(nullptr) {
      DCHECK_NE(THIS_VARIABLE, variable_kind);
      bit_field_ |= IsAssignedField::encode(false) |
                    IsResolvedField::encode(false) |
                    IsRemovedFromUnresolvedField::encode(false) |
                    HoleCheckModeField::encode(HoleCheckMode::kElided);
    }
  
    explicit VariableProxy(const VariableProxy* copy_from);
  
    class IsAssignedField
        : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
    class IsResolvedField : public BitField<bool, IsAssignedField::kNext, 1> {};
    class IsRemovedFromUnresolvedField
        : public BitField<bool, IsResolvedField::kNext, 1> {};
    class IsNewTargetField
        : public BitField<bool, IsRemovedFromUnresolvedField::kNext, 1> {};
    class HoleCheckModeField
        : public BitField<HoleCheckMode, IsNewTargetField::kNext, 1> {};
  
    union {
      const AstRawString* raw_name_;  // if !is_resolved_
      Variable* var_;                 // if is_resolved_
    };
  
    V8_INLINE VariableProxy** next() { return &next_unresolved_; }
    VariableProxy* next_unresolved_;
  
    friend base::ThreadedListTraits<VariableProxy>;
  };
  
  // Assignments to a property will use one of several types of property access.
  // Otherwise, the assignment is to a non-property (a global, a local slot, a
  // parameter slot, or a destructuring pattern).
  enum AssignType {
    NON_PROPERTY,
    NAMED_PROPERTY,
    KEYED_PROPERTY,
    NAMED_SUPER_PROPERTY,
    KEYED_SUPER_PROPERTY
  };
  
  class Property final : public Expression {
   public:
    bool IsValidReferenceExpression() const { return true; }
  
    Expression* obj() const { return obj_; }
    Expression* key() const { return key_; }
  
    bool IsSuperAccess() { return obj()->IsSuperPropertyReference(); }
  
    // Returns the properties assign type.
    static AssignType GetAssignType(Property* property) {
      if (property == nullptr) return NON_PROPERTY;
      bool super_access = property->IsSuperAccess();
      return (property->key()->IsPropertyName())
                 ? (super_access ? NAMED_SUPER_PROPERTY : NAMED_PROPERTY)
                 : (super_access ? KEYED_SUPER_PROPERTY : KEYED_PROPERTY);
    }
  
   private:
    friend class AstNodeFactory;
  
    Property(Expression* obj, Expression* key, int pos)
        : Expression(pos, kProperty), obj_(obj), key_(key) {
    }
  
    Expression* obj_;
    Expression* key_;
  };
  
  // ResolvedProperty pairs a receiver field with a value field. It allows Call
  // to support arbitrary receivers while still taking advantage of TypeFeedback.
  class ResolvedProperty final : public Expression {
   public:
    VariableProxy* object() const { return object_; }
    VariableProxy* property() const { return property_; }
  
    void set_object(VariableProxy* e) { object_ = e; }
    void set_property(VariableProxy* e) { property_ = e; }
  
   private:
    friend class AstNodeFactory;
  
    ResolvedProperty(VariableProxy* obj, VariableProxy* property, int pos)
        : Expression(pos, kResolvedProperty), object_(obj), property_(property) {}
  
    VariableProxy* object_;
    VariableProxy* property_;
  };
  
  class Call final : public Expression {
   public:
    Expression* expression() const { return expression_; }
    const ZonePtrList<Expression>* arguments() const { return &arguments_; }
  
    bool is_possibly_eval() const {
      return IsPossiblyEvalField::decode(bit_field_);
    }
  
    bool is_tagged_template() const {
      return IsTaggedTemplateField::decode(bit_field_);
    }
  
    bool only_last_arg_is_spread() {
      return !arguments_.is_empty() && arguments_.last()->IsSpread();
    }
  
    enum CallType {
      GLOBAL_CALL,
      WITH_CALL,
      NAMED_PROPERTY_CALL,
      KEYED_PROPERTY_CALL,
      NAMED_SUPER_PROPERTY_CALL,
      KEYED_SUPER_PROPERTY_CALL,
      SUPER_CALL,
      RESOLVED_PROPERTY_CALL,
      OTHER_CALL
    };
  
    enum PossiblyEval {
      IS_POSSIBLY_EVAL,
      NOT_EVAL,
    };
  
    // Helpers to determine how to handle the call.
    CallType GetCallType() const;
  
    enum class TaggedTemplateTag { kTrue };
  
   private:
    friend class AstNodeFactory;
  
    Call(Zone* zone, Expression* expression,
         const ScopedPtrList<Expression>& arguments, int pos,
         PossiblyEval possibly_eval)
        : Expression(pos, kCall),
          expression_(expression),
          arguments_(0, nullptr) {
      bit_field_ |=
          IsPossiblyEvalField::encode(possibly_eval == IS_POSSIBLY_EVAL) |
          IsTaggedTemplateField::encode(false);
      arguments.CopyTo(&arguments_, zone);
    }
  
    Call(Zone* zone, Expression* expression,
         const ScopedPtrList<Expression>& arguments, int pos,
         TaggedTemplateTag tag)
        : Expression(pos, kCall),
          expression_(expression),
          arguments_(0, nullptr) {
      bit_field_ |= IsPossiblyEvalField::encode(false) |
                    IsTaggedTemplateField::encode(true);
      arguments.CopyTo(&arguments_, zone);
    }
  
    class IsPossiblyEvalField
        : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
    class IsTaggedTemplateField
        : public BitField<bool, IsPossiblyEvalField::kNext, 1> {};
  
    Expression* expression_;
    ZonePtrList<Expression> arguments_;
  };
  
  
  class CallNew final : public Expression {
   public:
    Expression* expression() const { return expression_; }
    const ZonePtrList<Expression>* arguments() const { return &arguments_; }
  
    bool only_last_arg_is_spread() {
      return !arguments_.is_empty() && arguments_.last()->IsSpread();
    }
  
   private:
    friend class AstNodeFactory;
  
    CallNew(Zone* zone, Expression* expression,
            const ScopedPtrList<Expression>& arguments, int pos)
        : Expression(pos, kCallNew),
          expression_(expression),
          arguments_(0, nullptr) {
      arguments.CopyTo(&arguments_, zone);
    }
  
    Expression* expression_;
    ZonePtrList<Expression> arguments_;
  };
  
  // The CallRuntime class does not represent any official JavaScript
  // language construct. Instead it is used to call a C or JS function
  // with a set of arguments. This is used from the builtins that are
  // implemented in JavaScript.
  class CallRuntime final : public Expression {
   public:
    const ZonePtrList<Expression>* arguments() const { return &arguments_; }
    bool is_jsruntime() const { return function_ == nullptr; }
  
    int context_index() const {
      DCHECK(is_jsruntime());
      return context_index_;
    }
    const Runtime::Function* function() const {
      DCHECK(!is_jsruntime());
      return function_;
    }
  
    const char* debug_name();
  
   private:
    friend class AstNodeFactory;
  
    CallRuntime(Zone* zone, const Runtime::Function* function,
                const ScopedPtrList<Expression>& arguments, int pos)
        : Expression(pos, kCallRuntime),
          function_(function),
          arguments_(0, nullptr) {
      arguments.CopyTo(&arguments_, zone);
    }
    CallRuntime(Zone* zone, int context_index,
                const ScopedPtrList<Expression>& arguments, int pos)
        : Expression(pos, kCallRuntime),
          context_index_(context_index),
          function_(nullptr),
          arguments_(0, nullptr) {
      arguments.CopyTo(&arguments_, zone);
    }
  
    int context_index_;
    const Runtime::Function* function_;
    ZonePtrList<Expression> arguments_;
  };
  
  
  class UnaryOperation final : public Expression {
   public:
    Token::Value op() const { return OperatorField::decode(bit_field_); }
    Expression* expression() const { return expression_; }
  
   private:
    friend class AstNodeFactory;
  
    UnaryOperation(Token::Value op, Expression* expression, int pos)
        : Expression(pos, kUnaryOperation), expression_(expression) {
      bit_field_ |= OperatorField::encode(op);
      DCHECK(Token::IsUnaryOp(op));
    }
  
    Expression* expression_;
  
    class OperatorField
        : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
  };
  
  
  class BinaryOperation final : public Expression {
   public:
    Token::Value op() const { return OperatorField::decode(bit_field_); }
    Expression* left() const { return left_; }
    Expression* right() const { return right_; }
  
    // Returns true if one side is a Smi literal, returning the other side's
    // sub-expression in |subexpr| and the literal Smi in |literal|.
    bool IsSmiLiteralOperation(Expression** subexpr, Smi* literal);
  
   private:
    friend class AstNodeFactory;
  
    BinaryOperation(Token::Value op, Expression* left, Expression* right, int pos)
        : Expression(pos, kBinaryOperation), left_(left), right_(right) {
      bit_field_ |= OperatorField::encode(op);
      DCHECK(Token::IsBinaryOp(op));
    }
  
    Expression* left_;
    Expression* right_;
  
    class OperatorField
        : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
  };
  
  class NaryOperation final : public Expression {
   public:
    Token::Value op() const { return OperatorField::decode(bit_field_); }
    Expression* first() const { return first_; }
    Expression* subsequent(size_t index) const {
      return subsequent_[index].expression;
    }
  
    size_t subsequent_length() const { return subsequent_.size(); }
    int subsequent_op_position(size_t index) const {
      return subsequent_[index].op_position;
    }
  
    void AddSubsequent(Expression* expr, int pos) {
      subsequent_.emplace_back(expr, pos);
    }
  
   private:
    friend class AstNodeFactory;
  
    NaryOperation(Zone* zone, Token::Value op, Expression* first,
                  size_t initial_subsequent_size)
        : Expression(first->position(), kNaryOperation),
          first_(first),
          subsequent_(zone) {
      bit_field_ |= OperatorField::encode(op);
      DCHECK(Token::IsBinaryOp(op));
      DCHECK_NE(op, Token::EXP);
      subsequent_.reserve(initial_subsequent_size);
    }
  
    // Nary operations store the first (lhs) child expression inline, and the
    // child expressions (rhs of each op) are stored out-of-line, along with
    // their operation's position. Note that the Nary operation expression's
    // position has no meaning.
    //
    // So an nary add:
    //
    //    expr + expr + expr + ...
    //
    // is stored as:
    //
    //    (expr) [(+ expr), (+ expr), ...]
    //    '-.--' '-----------.-----------'
    //    first    subsequent entry list
  
    Expression* first_;
  
    struct NaryOperationEntry {
      Expression* expression;
      int op_position;
      NaryOperationEntry(Expression* e, int pos)
          : expression(e), op_position(pos) {}
    };
    ZoneVector<NaryOperationEntry> subsequent_;
  
    class OperatorField
        : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
  };
  
  class CountOperation final : public Expression {
   public:
    bool is_prefix() const { return IsPrefixField::decode(bit_field_); }
    bool is_postfix() const { return !is_prefix(); }
  
    Token::Value op() const { return TokenField::decode(bit_field_); }
  
    Expression* expression() const { return expression_; }
  
   private:
    friend class AstNodeFactory;
  
    CountOperation(Token::Value op, bool is_prefix, Expression* expr, int pos)
        : Expression(pos, kCountOperation), expression_(expr) {
      bit_field_ |= IsPrefixField::encode(is_prefix) | TokenField::encode(op);
    }
  
    class IsPrefixField
        : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
    class TokenField : public BitField<Token::Value, IsPrefixField::kNext, 7> {};
  
    Expression* expression_;
  };
  
  
  class CompareOperation final : public Expression {
   public:
    Token::Value op() const { return OperatorField::decode(bit_field_); }
    Expression* left() const { return left_; }
    Expression* right() const { return right_; }
  
    // Match special cases.
    bool IsLiteralCompareTypeof(Expression** expr, Literal** literal);
    bool IsLiteralCompareUndefined(Expression** expr);
    bool IsLiteralCompareNull(Expression** expr);
  
   private:
    friend class AstNodeFactory;
  
    CompareOperation(Token::Value op, Expression* left, Expression* right,
                     int pos)
        : Expression(pos, kCompareOperation), left_(left), right_(right) {
      bit_field_ |= OperatorField::encode(op);
      DCHECK(Token::IsCompareOp(op));
    }
  
    Expression* left_;
    Expression* right_;
  
    class OperatorField
        : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
  };
  
  
  class Spread final : public Expression {
   public:
    Expression* expression() const { return expression_; }
  
    int expression_position() const { return expr_pos_; }
  
   private:
    friend class AstNodeFactory;
  
    Spread(Expression* expression, int pos, int expr_pos)
        : Expression(pos, kSpread),
          expr_pos_(expr_pos),
          expression_(expression) {}
  
    int expr_pos_;
    Expression* expression_;
  };
  
  // The StoreInArrayLiteral node corresponds to the StaInArrayLiteral bytecode.
  // It is used in the rewriting of destructuring assignments that contain an
  // array rest pattern.
  class StoreInArrayLiteral final : public Expression {
   public:
    Expression* array() const { return array_; }
    Expression* index() const { return index_; }
    Expression* value() const { return value_; }
  
   private:
    friend class AstNodeFactory;
  
    StoreInArrayLiteral(Expression* array, Expression* index, Expression* value,
                        int position)
        : Expression(position, kStoreInArrayLiteral),
          array_(array),
          index_(index),
          value_(value) {}
  
    Expression* array_;
    Expression* index_;
    Expression* value_;
  };
  
  class Conditional final : public Expression {
   public:
    Expression* condition() const { return condition_; }
    Expression* then_expression() const { return then_expression_; }
    Expression* else_expression() const { return else_expression_; }
  
   private:
    friend class AstNodeFactory;
  
    Conditional(Expression* condition, Expression* then_expression,
                Expression* else_expression, int position)
        : Expression(position, kConditional),
          condition_(condition),
          then_expression_(then_expression),
          else_expression_(else_expression) {}
  
    Expression* condition_;
    Expression* then_expression_;
    Expression* else_expression_;
  };
  
  class Assignment : public Expression {
   public:
    Token::Value op() const { return TokenField::decode(bit_field_); }
    Expression* target() const { return target_; }
    Expression* value() const { return value_; }
  
    // The assignment was generated as part of block-scoped sloppy-mode
    // function hoisting, see
    // ES#sec-block-level-function-declarations-web-legacy-compatibility-semantics
    LookupHoistingMode lookup_hoisting_mode() const {
      return static_cast<LookupHoistingMode>(
          LookupHoistingModeField::decode(bit_field_));
    }
    void set_lookup_hoisting_mode(LookupHoistingMode mode) {
      bit_field_ =
          LookupHoistingModeField::update(bit_field_, static_cast<bool>(mode));
    }
  
   protected:
    Assignment(NodeType type, Token::Value op, Expression* target,
               Expression* value, int pos);
  
   private:
    friend class AstNodeFactory;
  
    class TokenField
        : public BitField<Token::Value, Expression::kNextBitFieldIndex, 7> {};
    class LookupHoistingModeField : public BitField<bool, TokenField::kNext, 1> {
    };
  
    Expression* target_;
    Expression* value_;
  };
  
  class CompoundAssignment final : public Assignment {
   public:
    BinaryOperation* binary_operation() const { return binary_operation_; }
  
   private:
    friend class AstNodeFactory;
  
    CompoundAssignment(Token::Value op, Expression* target, Expression* value,
                       int pos, BinaryOperation* binary_operation)
        : Assignment(kCompoundAssignment, op, target, value, pos),
          binary_operation_(binary_operation) {}
  
    BinaryOperation* binary_operation_;
  };
  
  // There are several types of Suspend node:
  //
  // Yield
  // YieldStar
  // Await
  //
  // Our Yield is different from the JS yield in that it "returns" its argument as
  // is, without wrapping it in an iterator result object.  Such wrapping, if
  // desired, must be done beforehand (see the parser).
  class Suspend : public Expression {
   public:
    // With {kNoControl}, the {Suspend} behaves like yield, except that it never
    // throws and never causes the current generator to return. This is used to
    // desugar yield*.
    // TODO(caitp): remove once yield* desugaring for async generators is handled
    // in BytecodeGenerator.
    enum OnAbruptResume { kOnExceptionThrow, kNoControl };
  
    Expression* expression() const { return expression_; }
    OnAbruptResume on_abrupt_resume() const {
      return OnAbruptResumeField::decode(bit_field_);
    }
  
   private:
    friend class AstNodeFactory;
    friend class Yield;
    friend class YieldStar;
    friend class Await;
  
    Suspend(NodeType node_type, Expression* expression, int pos,
            OnAbruptResume on_abrupt_resume)
        : Expression(pos, node_type), expression_(expression) {
      bit_field_ |= OnAbruptResumeField::encode(on_abrupt_resume);
    }
  
    Expression* expression_;
  
    class OnAbruptResumeField
        : public BitField<OnAbruptResume, Expression::kNextBitFieldIndex, 1> {};
  };
  
  class Yield final : public Suspend {
   private:
    friend class AstNodeFactory;
    Yield(Expression* expression, int pos, OnAbruptResume on_abrupt_resume)
        : Suspend(kYield, expression, pos, on_abrupt_resume) {}
  };
  
  class YieldStar final : public Suspend {
   private:
    friend class AstNodeFactory;
    YieldStar(Expression* expression, int pos)
        : Suspend(kYieldStar, expression, pos,
                  Suspend::OnAbruptResume::kNoControl) {}
  };
  
  class Await final : public Suspend {
   private:
    friend class AstNodeFactory;
  
    Await(Expression* expression, int pos)
        : Suspend(kAwait, expression, pos, Suspend::kOnExceptionThrow) {}
  };
  
  class Throw final : public Expression {
   public:
    Expression* exception() const { return exception_; }
  
   private:
    friend class AstNodeFactory;
  
    Throw(Expression* exception, int pos)
        : Expression(pos, kThrow), exception_(exception) {}
  
    Expression* exception_;
  };
  
  
  class FunctionLiteral final : public Expression {
   public:
    enum FunctionType {
      kAnonymousExpression,
      kNamedExpression,
      kDeclaration,
      kAccessorOrMethod,
      kWrapped,
    };
  
    enum IdType { kIdTypeInvalid = -1, kIdTypeTopLevel = 0 };
  
    enum ParameterFlag : uint8_t {
      kNoDuplicateParameters,
      kHasDuplicateParameters
    };
    enum EagerCompileHint : uint8_t { kShouldEagerCompile, kShouldLazyCompile };
  
    // Empty handle means that the function does not have a shared name (i.e.
    // the name will be set dynamically after creation of the function closure).
    MaybeHandle<String> name() const {
      return raw_name_ ? raw_name_->string() : MaybeHandle<String>();
    }
    Handle<String> name(Isolate* isolate) const;
    bool has_shared_name() const { return raw_name_ != nullptr; }
    const AstConsString* raw_name() const { return raw_name_; }
    void set_raw_name(const AstConsString* name) { raw_name_ = name; }
    DeclarationScope* scope() const { return scope_; }
    ZonePtrList<Statement>* body() { return &body_; }
    void set_function_token_position(int pos) { function_token_position_ = pos; }
    int function_token_position() const { return function_token_position_; }
    int start_position() const;
    int end_position() const;
    bool is_declaration() const { return function_type() == kDeclaration; }
    bool is_named_expression() const {
      return function_type() == kNamedExpression;
    }
    bool is_anonymous_expression() const {
      return function_type() == kAnonymousExpression;
    }
  
    void mark_as_oneshot_iife() {
      bit_field_ = OneshotIIFEBit::update(bit_field_, true);
    }
    bool is_oneshot_iife() const { return OneshotIIFEBit::decode(bit_field_); }
    bool is_toplevel() const {
      return function_literal_id() == FunctionLiteral::kIdTypeTopLevel;
    }
    bool is_wrapped() const { return function_type() == kWrapped; }
    LanguageMode language_mode() const;
  
    static bool NeedsHomeObject(Expression* expr);
  
    int expected_property_count() {
      // Not valid for lazy functions.
      DCHECK(ShouldEagerCompile());
      return expected_property_count_;
    }
    int parameter_count() { return parameter_count_; }
    int function_length() { return function_length_; }
  
    bool AllowsLazyCompilation();
  
    bool CanSuspend() {
      if (suspend_count() > 0) {
        DCHECK(IsResumableFunction(kind()));
        return true;
      }
      return false;
    }
  
    // Returns either name or inferred name as a cstring.
    std::unique_ptr<char[]> GetDebugName() const;
  
    Handle<String> inferred_name() const {
      if (!inferred_name_.is_null()) {
        DCHECK_NULL(raw_inferred_name_);
        return inferred_name_;
      }
      if (raw_inferred_name_ != nullptr) {
        return raw_inferred_name_->string();
      }
      UNREACHABLE();
    }
    const AstConsString* raw_inferred_name() { return raw_inferred_name_; }
  
    // Only one of {set_inferred_name, set_raw_inferred_name} should be called.
    void set_inferred_name(Handle<String> inferred_name);
    void set_raw_inferred_name(const AstConsString* raw_inferred_name);
  
    bool pretenure() const { return Pretenure::decode(bit_field_); }
    void set_pretenure() { bit_field_ = Pretenure::update(bit_field_, true); }
  
    bool has_duplicate_parameters() const {
      // Not valid for lazy functions.
      DCHECK(ShouldEagerCompile());
      return HasDuplicateParameters::decode(bit_field_);
    }
  
    // This is used as a heuristic on when to eagerly compile a function
    // literal. We consider the following constructs as hints that the
    // function will be called immediately:
    // - (function() { ... })();
    // - var x = function() { ... }();
    bool ShouldEagerCompile() const;
    V8_EXPORT_PRIVATE void SetShouldEagerCompile();
  
    FunctionType function_type() const {
      return FunctionTypeBits::decode(bit_field_);
    }
    FunctionKind kind() const;
  
    bool dont_optimize() {
      return dont_optimize_reason() != BailoutReason::kNoReason;
    }
    BailoutReason dont_optimize_reason() {
      return DontOptimizeReasonField::decode(bit_field_);
    }
    void set_dont_optimize_reason(BailoutReason reason) {
      bit_field_ = DontOptimizeReasonField::update(bit_field_, reason);
    }
  
    bool IsAnonymousFunctionDefinition() const {
      return is_anonymous_expression();
    }
  
    int suspend_count() { return suspend_count_; }
    void set_suspend_count(int suspend_count) { suspend_count_ = suspend_count; }
  
    int return_position() {
      return std::max(
          start_position(),
          end_position() - (HasBracesField::decode(bit_field_) ? 1 : 0));
    }
  
    int function_literal_id() const { return function_literal_id_; }
    void set_function_literal_id(int function_literal_id) {
      function_literal_id_ = function_literal_id;
    }
  
    void set_requires_instance_members_initializer(bool value) {
      bit_field_ = RequiresInstanceMembersInitializer::update(bit_field_, value);
    }
    bool requires_instance_members_initializer() const {
      return RequiresInstanceMembersInitializer::decode(bit_field_);
    }
  
    ProducedPreparseData* produced_preparse_data() const {
      return produced_preparse_data_;
    }
  
   private:
    friend class AstNodeFactory;
  
    FunctionLiteral(Zone* zone, const AstRawString* name,
                    AstValueFactory* ast_value_factory, DeclarationScope* scope,
                    const ScopedPtrList<Statement>& body,
                    int expected_property_count, int parameter_count,
                    int function_length, FunctionType function_type,
                    ParameterFlag has_duplicate_parameters,
                    EagerCompileHint eager_compile_hint, int position,
                    bool has_braces, int function_literal_id,
                    ProducedPreparseData* produced_preparse_data = nullptr)
        : Expression(position, kFunctionLiteral),
          expected_property_count_(expected_property_count),
          parameter_count_(parameter_count),
          function_length_(function_length),
          function_token_position_(kNoSourcePosition),
          suspend_count_(0),
          function_literal_id_(function_literal_id),
          raw_name_(name ? ast_value_factory->NewConsString(name) : nullptr),
          scope_(scope),
          body_(0, nullptr),
          raw_inferred_name_(ast_value_factory->empty_cons_string()),
          produced_preparse_data_(produced_preparse_data) {
      bit_field_ |=
          FunctionTypeBits::encode(function_type) | Pretenure::encode(false) |
          HasDuplicateParameters::encode(has_duplicate_parameters ==
                                         kHasDuplicateParameters) |
          DontOptimizeReasonField::encode(BailoutReason::kNoReason) |
          RequiresInstanceMembersInitializer::encode(false) |
          HasBracesField::encode(has_braces) | OneshotIIFEBit::encode(false);
      if (eager_compile_hint == kShouldEagerCompile) SetShouldEagerCompile();
      body.CopyTo(&body_, zone);
    }
  
    class FunctionTypeBits
        : public BitField<FunctionType, Expression::kNextBitFieldIndex, 3> {};
    class Pretenure : public BitField<bool, FunctionTypeBits::kNext, 1> {};
    class HasDuplicateParameters : public BitField<bool, Pretenure::kNext, 1> {};
    class DontOptimizeReasonField
        : public BitField<BailoutReason, HasDuplicateParameters::kNext, 8> {};
    class RequiresInstanceMembersInitializer
        : public BitField<bool, DontOptimizeReasonField::kNext, 1> {};
    class HasBracesField
        : public BitField<bool, RequiresInstanceMembersInitializer::kNext, 1> {};
    class OneshotIIFEBit : public BitField<bool, HasBracesField::kNext, 1> {};
  
    int expected_property_count_;
    int parameter_count_;
    int function_length_;
    int function_token_position_;
    int suspend_count_;
    int function_literal_id_;
  
    const AstConsString* raw_name_;
    DeclarationScope* scope_;
    ZonePtrList<Statement> body_;
    const AstConsString* raw_inferred_name_;
    Handle<String> inferred_name_;
    ProducedPreparseData* produced_preparse_data_;
  };
  
  // Property is used for passing information
  // about a class literal's properties from the parser to the code generator.
  class ClassLiteralProperty final : public LiteralProperty {
   public:
    enum Kind : uint8_t { METHOD, GETTER, SETTER, FIELD };
  
    Kind kind() const { return kind_; }
  
    bool is_static() const { return is_static_; }
  
    bool is_private() const { return is_private_; }
  
    void set_computed_name_var(Variable* var) {
      DCHECK_EQ(FIELD, kind());
      DCHECK(!is_private());
      private_or_computed_name_var_ = var;
    }
  
    Variable* computed_name_var() const {
      DCHECK_EQ(FIELD, kind());
      DCHECK(!is_private());
      return private_or_computed_name_var_;
    }
  
    void set_private_name_var(Variable* var) {
      DCHECK_EQ(FIELD, kind());
      DCHECK(is_private());
      private_or_computed_name_var_ = var;
    }
    Variable* private_name_var() const {
      DCHECK_EQ(FIELD, kind());
      DCHECK(is_private());
      return private_or_computed_name_var_;
    }
  
   private:
    friend class AstNodeFactory;
  
    ClassLiteralProperty(Expression* key, Expression* value, Kind kind,
                         bool is_static, bool is_computed_name, bool is_private);
  
    Kind kind_;
    bool is_static_;
    bool is_private_;
    Variable* private_or_computed_name_var_;
  };
  
  class InitializeClassMembersStatement final : public Statement {
   public:
    typedef ClassLiteralProperty Property;
  
    ZonePtrList<Property>* fields() const { return fields_; }
  
   private:
    friend class AstNodeFactory;
  
    InitializeClassMembersStatement(ZonePtrList<Property>* fields, int pos)
        : Statement(pos, kInitializeClassMembersStatement), fields_(fields) {}
  
    ZonePtrList<Property>* fields_;
  };
  
  class ClassLiteral final : public Expression {
   public:
    typedef ClassLiteralProperty Property;
  
    Scope* scope() const { return scope_; }
    Variable* class_variable() const { return class_variable_; }
    Expression* extends() const { return extends_; }
    FunctionLiteral* constructor() const { return constructor_; }
    ZonePtrList<Property>* properties() const { return properties_; }
    int start_position() const { return position(); }
    int end_position() const { return end_position_; }
    bool has_name_static_property() const {
      return HasNameStaticProperty::decode(bit_field_);
    }
    bool has_static_computed_names() const {
      return HasStaticComputedNames::decode(bit_field_);
    }
  
    bool is_anonymous_expression() const {
      return IsAnonymousExpression::decode(bit_field_);
    }
    bool IsAnonymousFunctionDefinition() const {
      return is_anonymous_expression();
    }
  
    FunctionLiteral* static_fields_initializer() const {
      return static_fields_initializer_;
    }
  
    FunctionLiteral* instance_members_initializer_function() const {
      return instance_members_initializer_function_;
    }
  
   private:
    friend class AstNodeFactory;
  
    ClassLiteral(Scope* scope, Variable* class_variable, Expression* extends,
                 FunctionLiteral* constructor, ZonePtrList<Property>* properties,
                 FunctionLiteral* static_fields_initializer,
                 FunctionLiteral* instance_members_initializer_function,
                 int start_position, int end_position,
                 bool has_name_static_property, bool has_static_computed_names,
                 bool is_anonymous)
        : Expression(start_position, kClassLiteral),
          end_position_(end_position),
          scope_(scope),
          class_variable_(class_variable),
          extends_(extends),
          constructor_(constructor),
          properties_(properties),
          static_fields_initializer_(static_fields_initializer),
          instance_members_initializer_function_(
              instance_members_initializer_function) {
      bit_field_ |= HasNameStaticProperty::encode(has_name_static_property) |
                    HasStaticComputedNames::encode(has_static_computed_names) |
                    IsAnonymousExpression::encode(is_anonymous);
    }
  
    int end_position_;
    Scope* scope_;
    Variable* class_variable_;
    Expression* extends_;
    FunctionLiteral* constructor_;
    ZonePtrList<Property>* properties_;
    FunctionLiteral* static_fields_initializer_;
    FunctionLiteral* instance_members_initializer_function_;
    class HasNameStaticProperty
        : public BitField<bool, Expression::kNextBitFieldIndex, 1> {};
    class HasStaticComputedNames
        : public BitField<bool, HasNameStaticProperty::kNext, 1> {};
    class IsAnonymousExpression
        : public BitField<bool, HasStaticComputedNames::kNext, 1> {};
  };
  
  
  class NativeFunctionLiteral final : public Expression {
   public:
    Handle<String> name() const { return name_->string(); }
    const AstRawString* raw_name() const { return name_; }
    v8::Extension* extension() const { return extension_; }
  
   private:
    friend class AstNodeFactory;
  
    NativeFunctionLiteral(const AstRawString* name, v8::Extension* extension,
                          int pos)
        : Expression(pos, kNativeFunctionLiteral),
          name_(name),
          extension_(extension) {}
  
    const AstRawString* name_;
    v8::Extension* extension_;
  };
  
  
  class SuperPropertyReference final : public Expression {
   public:
    Expression* home_object() const { return home_object_; }
  
   private:
    friend class AstNodeFactory;
  
    // We take in ThisExpression* only as a proof that it was accessed.
    SuperPropertyReference(Expression* home_object, int pos)
        : Expression(pos, kSuperPropertyReference), home_object_(home_object) {
      DCHECK(home_object->IsProperty());
    }
  
    Expression* home_object_;
  };
  
  
  class SuperCallReference final : public Expression {
   public:
    VariableProxy* new_target_var() const { return new_target_var_; }
    VariableProxy* this_function_var() const { return this_function_var_; }
  
   private:
    friend class AstNodeFactory;
  
    // We take in ThisExpression* only as a proof that it was accessed.
    SuperCallReference(VariableProxy* new_target_var,
                       VariableProxy* this_function_var, int pos)
        : Expression(pos, kSuperCallReference),
          new_target_var_(new_target_var),
          this_function_var_(this_function_var) {
      DCHECK(new_target_var->raw_name()->IsOneByteEqualTo(".new.target"));
      DCHECK(this_function_var->raw_name()->IsOneByteEqualTo(".this_function"));
    }
  
    VariableProxy* new_target_var_;
    VariableProxy* this_function_var_;
  };
  
  // This AST Node is used to represent a dynamic import call --
  // import(argument).
  class ImportCallExpression final : public Expression {
   public:
    Expression* argument() const { return argument_; }
  
   private:
    friend class AstNodeFactory;
  
    ImportCallExpression(Expression* argument, int pos)
        : Expression(pos, kImportCallExpression), argument_(argument) {}
  
    Expression* argument_;
  };
  
  // This class is produced when parsing the () in arrow functions without any
  // arguments and is not actually a valid expression.
  class EmptyParentheses final : public Expression {
   private:
    friend class AstNodeFactory;
  
    explicit EmptyParentheses(int pos) : Expression(pos, kEmptyParentheses) {
      mark_parenthesized();
    }
  };
  
  // Represents the spec operation `GetTemplateObject(templateLiteral)`
  // (defined at https://tc39.github.io/ecma262/#sec-gettemplateobject).
  class GetTemplateObject final : public Expression {
   public:
    const ZonePtrList<const AstRawString>* cooked_strings() const {
      return cooked_strings_;
    }
    const ZonePtrList<const AstRawString>* raw_strings() const {
      return raw_strings_;
    }
  
    Handle<TemplateObjectDescription> GetOrBuildDescription(Isolate* isolate);
  
   private:
    friend class AstNodeFactory;
  
    GetTemplateObject(const ZonePtrList<const AstRawString>* cooked_strings,
                      const ZonePtrList<const AstRawString>* raw_strings, int pos)
        : Expression(pos, kGetTemplateObject),
          cooked_strings_(cooked_strings),
          raw_strings_(raw_strings) {}
  
    const ZonePtrList<const AstRawString>* cooked_strings_;
    const ZonePtrList<const AstRawString>* raw_strings_;
  };
  
  class TemplateLiteral final : public Expression {
   public:
    const ZonePtrList<const AstRawString>* string_parts() const {
      return string_parts_;
    }
    const ZonePtrList<Expression>* substitutions() const {
      return substitutions_;
    }
  
   private:
    friend class AstNodeFactory;
    TemplateLiteral(const ZonePtrList<const AstRawString>* parts,
                    const ZonePtrList<Expression>* substitutions, int pos)
        : Expression(pos, kTemplateLiteral),
          string_parts_(parts),
          substitutions_(substitutions) {}
  
    const ZonePtrList<const AstRawString>* string_parts_;
    const ZonePtrList<Expression>* substitutions_;
  };
  
  // ----------------------------------------------------------------------------
  // Basic visitor
  // Sub-class should parametrize AstVisitor with itself, e.g.:
  //   class SpecificVisitor : public AstVisitor<SpecificVisitor> { ... }
  
  template <class Subclass>
  class AstVisitor {
   public:
    void Visit(AstNode* node) { impl()->Visit(node); }
  
    void VisitDeclarations(Declaration::List* declarations) {
      for (Declaration* decl : *declarations) Visit(decl);
    }
  
    void VisitStatements(const ZonePtrList<Statement>* statements) {
      for (int i = 0; i < statements->length(); i++) {
        Statement* stmt = statements->at(i);
        Visit(stmt);
        if (stmt->IsJump()) break;
      }
    }
  
    void VisitExpressions(const ZonePtrList<Expression>* expressions) {
      for (int i = 0; i < expressions->length(); i++) {
        // The variable statement visiting code may pass null expressions
        // to this code. Maybe this should be handled by introducing an
        // undefined expression or literal? Revisit this code if this
        // changes.
        Expression* expression = expressions->at(i);
        if (expression != nullptr) Visit(expression);
      }
    }
  
   protected:
    Subclass* impl() { return static_cast<Subclass*>(this); }
  };
  
  #define GENERATE_VISIT_CASE(NodeType)                                   \
    case AstNode::k##NodeType:                                            \
      return this->impl()->Visit##NodeType(static_cast<NodeType*>(node));
  
  #define GENERATE_FAILURE_CASE(NodeType) \
    case AstNode::k##NodeType:            \
      UNREACHABLE();
  
  #define GENERATE_AST_VISITOR_SWITCH()        \
    switch (node->node_type()) {               \
      AST_NODE_LIST(GENERATE_VISIT_CASE)       \
      FAILURE_NODE_LIST(GENERATE_FAILURE_CASE) \
    }
  
  #define DEFINE_AST_VISITOR_SUBCLASS_MEMBERS()               \
   public:                                                    \
    void VisitNoStackOverflowCheck(AstNode* node) {           \
      GENERATE_AST_VISITOR_SWITCH()                           \
    }                                                         \
                                                              \
    void Visit(AstNode* node) {                               \
      if (CheckStackOverflow()) return;                       \
      VisitNoStackOverflowCheck(node);                        \
    }                                                         \
                                                              \
    void SetStackOverflow() { stack_overflow_ = true; }       \
    void ClearStackOverflow() { stack_overflow_ = false; }    \
    bool HasStackOverflow() const { return stack_overflow_; } \
                                                              \
    bool CheckStackOverflow() {                               \
      if (stack_overflow_) return true;                       \
      if (GetCurrentStackPosition() < stack_limit_) {         \
        stack_overflow_ = true;                               \
        return true;                                          \
      }                                                       \
      return false;                                           \
    }                                                         \
                                                              \
   private:                                                   \
    void InitializeAstVisitor(Isolate* isolate) {             \
      stack_limit_ = isolate->stack_guard()->real_climit();   \
      stack_overflow_ = false;                                \
    }                                                         \
                                                              \
    void InitializeAstVisitor(uintptr_t stack_limit) {        \
      stack_limit_ = stack_limit;                             \
      stack_overflow_ = false;                                \
    }                                                         \
                                                              \
    uintptr_t stack_limit_;                                   \
    bool stack_overflow_
  
  #define DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()    \
   public:                                                      \
    void Visit(AstNode* node) { GENERATE_AST_VISITOR_SWITCH() } \
                                                                \
   private:
  
  // ----------------------------------------------------------------------------
  // AstNode factory
  
  class AstNodeFactory final {
   public:
    AstNodeFactory(AstValueFactory* ast_value_factory, Zone* zone)
        : zone_(zone),
          ast_value_factory_(ast_value_factory),
          empty_statement_(new (zone) class EmptyStatement()),
          this_expression_(new (zone) class ThisExpression()),
          failure_expression_(new (zone) class FailureExpression()) {}
  
    AstNodeFactory* ast_node_factory() { return this; }
    AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
  
    VariableDeclaration* NewVariableDeclaration(int pos) {
      return new (zone_) VariableDeclaration(pos);
    }
  
    NestedVariableDeclaration* NewNestedVariableDeclaration(Scope* scope,
                                                            int pos) {
      return new (zone_) NestedVariableDeclaration(scope, pos);
    }
  
    FunctionDeclaration* NewFunctionDeclaration(FunctionLiteral* fun, int pos) {
      return new (zone_) FunctionDeclaration(fun, pos);
    }
  
    Block* NewBlock(int capacity, bool ignore_completion_value) {
      return new (zone_) Block(zone_, nullptr, capacity, ignore_completion_value);
    }
  
    Block* NewBlock(bool ignore_completion_value,
                    ZonePtrList<const AstRawString>* labels) {
      return labels != nullptr
                 ? new (zone_) LabeledBlock(labels, ignore_completion_value)
                 : new (zone_) Block(labels, ignore_completion_value);
    }
  
    Block* NewBlock(bool ignore_completion_value,
                    const ScopedPtrList<Statement>& statements) {
      Block* result = NewBlock(ignore_completion_value, nullptr);
      result->InitializeStatements(statements, zone_);
      return result;
    }
  
  #define STATEMENT_WITH_LABELS(NodeType)                                \
    NodeType* New##NodeType(ZonePtrList<const AstRawString>* labels,     \
                            ZonePtrList<const AstRawString>* own_labels, \
                            int pos) {                                   \
      return new (zone_) NodeType(labels, own_labels, pos);              \
    }
    STATEMENT_WITH_LABELS(DoWhileStatement)
    STATEMENT_WITH_LABELS(WhileStatement)
    STATEMENT_WITH_LABELS(ForStatement)
  #undef STATEMENT_WITH_LABELS
  
    SwitchStatement* NewSwitchStatement(ZonePtrList<const AstRawString>* labels,
                                        Expression* tag, int pos) {
      return new (zone_) SwitchStatement(zone_, labels, tag, pos);
    }
  
    ForEachStatement* NewForEachStatement(
        ForEachStatement::VisitMode visit_mode,
        ZonePtrList<const AstRawString>* labels,
        ZonePtrList<const AstRawString>* own_labels, int pos) {
      switch (visit_mode) {
        case ForEachStatement::ENUMERATE: {
          return new (zone_) ForInStatement(labels, own_labels, pos);
        }
        case ForEachStatement::ITERATE: {
          return new (zone_)
              ForOfStatement(labels, own_labels, pos, IteratorType::kNormal);
        }
      }
      UNREACHABLE();
    }
  
    ForOfStatement* NewForOfStatement(ZonePtrList<const AstRawString>* labels,
                                      ZonePtrList<const AstRawString>* own_labels,
                                      int pos, IteratorType type) {
      return new (zone_) ForOfStatement(labels, own_labels, pos, type);
    }
  
    ExpressionStatement* NewExpressionStatement(Expression* expression, int pos) {
      return new (zone_) ExpressionStatement(expression, pos);
    }
  
    ContinueStatement* NewContinueStatement(IterationStatement* target, int pos) {
      return new (zone_) ContinueStatement(target, pos);
    }
  
    BreakStatement* NewBreakStatement(BreakableStatement* target, int pos) {
      return new (zone_) BreakStatement(target, pos);
    }
  
    ReturnStatement* NewReturnStatement(Expression* expression, int pos,
                                        int end_position = kNoSourcePosition) {
      return new (zone_) ReturnStatement(expression, ReturnStatement::kNormal,
                                         pos, end_position);
    }
  
    ReturnStatement* NewAsyncReturnStatement(
        Expression* expression, int pos, int end_position = kNoSourcePosition) {
      return new (zone_) ReturnStatement(
          expression, ReturnStatement::kAsyncReturn, pos, end_position);
    }
  
    WithStatement* NewWithStatement(Scope* scope,
                                    Expression* expression,
                                    Statement* statement,
                                    int pos) {
      return new (zone_) WithStatement(scope, expression, statement, pos);
    }
  
    IfStatement* NewIfStatement(Expression* condition, Statement* then_statement,
                                Statement* else_statement, int pos) {
      return new (zone_)
          IfStatement(condition, then_statement, else_statement, pos);
    }
  
    TryCatchStatement* NewTryCatchStatement(Block* try_block, Scope* scope,
                                            Block* catch_block, int pos) {
      return new (zone_) TryCatchStatement(try_block, scope, catch_block,
                                           HandlerTable::CAUGHT, pos);
    }
  
    TryCatchStatement* NewTryCatchStatementForReThrow(Block* try_block,
                                                      Scope* scope,
                                                      Block* catch_block,
                                                      int pos) {
      return new (zone_) TryCatchStatement(try_block, scope, catch_block,
                                           HandlerTable::UNCAUGHT, pos);
    }
  
    TryCatchStatement* NewTryCatchStatementForDesugaring(Block* try_block,
                                                         Scope* scope,
                                                         Block* catch_block,
                                                         int pos) {
      return new (zone_) TryCatchStatement(try_block, scope, catch_block,
                                           HandlerTable::DESUGARING, pos);
    }
  
    TryCatchStatement* NewTryCatchStatementForAsyncAwait(Block* try_block,
                                                         Scope* scope,
                                                         Block* catch_block,
                                                         int pos) {
      return new (zone_) TryCatchStatement(try_block, scope, catch_block,
                                           HandlerTable::ASYNC_AWAIT, pos);
    }
  
    TryFinallyStatement* NewTryFinallyStatement(Block* try_block,
                                                Block* finally_block, int pos) {
      return new (zone_) TryFinallyStatement(try_block, finally_block, pos);
    }
  
    DebuggerStatement* NewDebuggerStatement(int pos) {
      return new (zone_) DebuggerStatement(pos);
    }
  
    class EmptyStatement* EmptyStatement() {
      return empty_statement_;
    }
  
    class ThisExpression* ThisExpression() {
      return this_expression_;
    }
  
    class FailureExpression* FailureExpression() {
      return failure_expression_;
    }
  
    SloppyBlockFunctionStatement* NewSloppyBlockFunctionStatement(
        int pos, Variable* var, Token::Value init) {
      return new (zone_)
          SloppyBlockFunctionStatement(pos, var, init, EmptyStatement());
    }
  
    CaseClause* NewCaseClause(Expression* label,
                              const ScopedPtrList<Statement>& statements) {
      return new (zone_) CaseClause(zone_, label, statements);
    }
  
    Literal* NewStringLiteral(const AstRawString* string, int pos) {
      DCHECK_NOT_NULL(string);
      return new (zone_) Literal(string, pos);
    }
  
    // A JavaScript symbol (ECMA-262 edition 6).
    Literal* NewSymbolLiteral(AstSymbol symbol, int pos) {
      return new (zone_) Literal(symbol, pos);
    }
  
    Literal* NewNumberLiteral(double number, int pos);
  
    Literal* NewSmiLiteral(int number, int pos) {
      return new (zone_) Literal(number, pos);
    }
  
    Literal* NewBigIntLiteral(AstBigInt bigint, int pos) {
      return new (zone_) Literal(bigint, pos);
    }
  
    Literal* NewBooleanLiteral(bool b, int pos) {
      return new (zone_) Literal(b, pos);
    }
  
    Literal* NewNullLiteral(int pos) {
      return new (zone_) Literal(Literal::kNull, pos);
    }
  
    Literal* NewUndefinedLiteral(int pos) {
      return new (zone_) Literal(Literal::kUndefined, pos);
    }
  
    Literal* NewTheHoleLiteral() {
      return new (zone_) Literal(Literal::kTheHole, kNoSourcePosition);
    }
  
    ObjectLiteral* NewObjectLiteral(
        const ScopedPtrList<ObjectLiteral::Property>& properties,
        uint32_t boilerplate_properties, int pos, bool has_rest_property) {
      return new (zone_) ObjectLiteral(zone_, properties, boilerplate_properties,
                                       pos, has_rest_property);
    }
  
    ObjectLiteral::Property* NewObjectLiteralProperty(
        Expression* key, Expression* value, ObjectLiteralProperty::Kind kind,
        bool is_computed_name) {
      return new (zone_)
          ObjectLiteral::Property(key, value, kind, is_computed_name);
    }
  
    ObjectLiteral::Property* NewObjectLiteralProperty(Expression* key,
                                                      Expression* value,
                                                      bool is_computed_name) {
      return new (zone_) ObjectLiteral::Property(ast_value_factory_, key, value,
                                                 is_computed_name);
    }
  
    RegExpLiteral* NewRegExpLiteral(const AstRawString* pattern, int flags,
                                    int pos) {
      return new (zone_) RegExpLiteral(pattern, flags, pos);
    }
  
    ArrayLiteral* NewArrayLiteral(const ScopedPtrList<Expression>& values,
                                  int pos) {
      return new (zone_) ArrayLiteral(zone_, values, -1, pos);
    }
  
    ArrayLiteral* NewArrayLiteral(const ScopedPtrList<Expression>& values,
                                  int first_spread_index, int pos) {
      return new (zone_) ArrayLiteral(zone_, values, first_spread_index, pos);
    }
  
    VariableProxy* NewVariableProxy(Variable* var,
                                    int start_position = kNoSourcePosition) {
      return new (zone_) VariableProxy(var, start_position);
    }
  
    VariableProxy* NewVariableProxy(const AstRawString* name,
                                    VariableKind variable_kind,
                                    int start_position = kNoSourcePosition) {
      DCHECK_NOT_NULL(name);
      return new (zone_) VariableProxy(name, variable_kind, start_position);
    }
  
    // Recreates the VariableProxy in this Zone.
    VariableProxy* CopyVariableProxy(VariableProxy* proxy) {
      return new (zone_) VariableProxy(proxy);
    }
  
    Variable* CopyVariable(Variable* variable) {
      return new (zone_) Variable(variable);
    }
  
    Property* NewProperty(Expression* obj, Expression* key, int pos) {
      return new (zone_) Property(obj, key, pos);
    }
  
    ResolvedProperty* NewResolvedProperty(VariableProxy* obj,
                                          VariableProxy* property,
                                          int pos = kNoSourcePosition) {
      return new (zone_) ResolvedProperty(obj, property, pos);
    }
  
    Call* NewCall(Expression* expression,
                  const ScopedPtrList<Expression>& arguments, int pos,
                  Call::PossiblyEval possibly_eval = Call::NOT_EVAL) {
      return new (zone_) Call(zone_, expression, arguments, pos, possibly_eval);
    }
  
    Call* NewTaggedTemplate(Expression* expression,
                            const ScopedPtrList<Expression>& arguments, int pos) {
      return new (zone_)
          Call(zone_, expression, arguments, pos, Call::TaggedTemplateTag::kTrue);
    }
  
    CallNew* NewCallNew(Expression* expression,
                        const ScopedPtrList<Expression>& arguments, int pos) {
      return new (zone_) CallNew(zone_, expression, arguments, pos);
    }
  
    CallRuntime* NewCallRuntime(Runtime::FunctionId id,
                                const ScopedPtrList<Expression>& arguments,
                                int pos) {
      return new (zone_)
          CallRuntime(zone_, Runtime::FunctionForId(id), arguments, pos);
    }
  
    CallRuntime* NewCallRuntime(const Runtime::Function* function,
                                const ScopedPtrList<Expression>& arguments,
                                int pos) {
      return new (zone_) CallRuntime(zone_, function, arguments, pos);
    }
  
    CallRuntime* NewCallRuntime(int context_index,
                                const ScopedPtrList<Expression>& arguments,
                                int pos) {
      return new (zone_) CallRuntime(zone_, context_index, arguments, pos);
    }
  
    UnaryOperation* NewUnaryOperation(Token::Value op,
                                      Expression* expression,
                                      int pos) {
      return new (zone_) UnaryOperation(op, expression, pos);
    }
  
    BinaryOperation* NewBinaryOperation(Token::Value op,
                                        Expression* left,
                                        Expression* right,
                                        int pos) {
      return new (zone_) BinaryOperation(op, left, right, pos);
    }
  
    NaryOperation* NewNaryOperation(Token::Value op, Expression* first,
                                    size_t initial_subsequent_size) {
      return new (zone_) NaryOperation(zone_, op, first, initial_subsequent_size);
    }
  
    CountOperation* NewCountOperation(Token::Value op,
                                      bool is_prefix,
                                      Expression* expr,
                                      int pos) {
      return new (zone_) CountOperation(op, is_prefix, expr, pos);
    }
  
    CompareOperation* NewCompareOperation(Token::Value op,
                                          Expression* left,
                                          Expression* right,
                                          int pos) {
      return new (zone_) CompareOperation(op, left, right, pos);
    }
  
    Spread* NewSpread(Expression* expression, int pos, int expr_pos) {
      return new (zone_) Spread(expression, pos, expr_pos);
    }
  
    StoreInArrayLiteral* NewStoreInArrayLiteral(Expression* array,
                                                Expression* index,
                                                Expression* value, int pos) {
      return new (zone_) StoreInArrayLiteral(array, index, value, pos);
    }
  
    Conditional* NewConditional(Expression* condition,
                                Expression* then_expression,
                                Expression* else_expression,
                                int position) {
      return new (zone_)
          Conditional(condition, then_expression, else_expression, position);
    }
  
    Assignment* NewAssignment(Token::Value op,
                              Expression* target,
                              Expression* value,
                              int pos) {
      DCHECK(Token::IsAssignmentOp(op));
      DCHECK_NOT_NULL(target);
      DCHECK_NOT_NULL(value);
  
      if (op != Token::INIT && target->IsVariableProxy()) {
        target->AsVariableProxy()->set_is_assigned();
      }
  
      if (op == Token::ASSIGN || op == Token::INIT) {
        return new (zone_)
            Assignment(AstNode::kAssignment, op, target, value, pos);
      } else {
        return new (zone_) CompoundAssignment(
            op, target, value, pos,
            NewBinaryOperation(Token::BinaryOpForAssignment(op), target, value,
                               pos + 1));
      }
    }
  
    Suspend* NewYield(Expression* expression, int pos,
                      Suspend::OnAbruptResume on_abrupt_resume) {
      if (!expression) expression = NewUndefinedLiteral(pos);
      return new (zone_) Yield(expression, pos, on_abrupt_resume);
    }
  
    YieldStar* NewYieldStar(Expression* expression, int pos) {
      return new (zone_) YieldStar(expression, pos);
    }
  
    Await* NewAwait(Expression* expression, int pos) {
      if (!expression) expression = NewUndefinedLiteral(pos);
      return new (zone_) Await(expression, pos);
    }
  
    Throw* NewThrow(Expression* exception, int pos) {
      return new (zone_) Throw(exception, pos);
    }
  
    FunctionLiteral* NewFunctionLiteral(
        const AstRawString* name, DeclarationScope* scope,
        const ScopedPtrList<Statement>& 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,
        ProducedPreparseData* produced_preparse_data = nullptr) {
      return new (zone_) FunctionLiteral(
          zone_, name, ast_value_factory_, scope, body, expected_property_count,
          parameter_count, function_length, function_type,
          has_duplicate_parameters, eager_compile_hint, position, has_braces,
          function_literal_id, produced_preparse_data);
    }
  
    // Creates a FunctionLiteral representing a top-level script, the
    // result of an eval (top-level or otherwise), or the result of calling
    // the Function constructor.
    FunctionLiteral* NewScriptOrEvalFunctionLiteral(
        DeclarationScope* scope, const ScopedPtrList<Statement>& body,
        int expected_property_count, int parameter_count) {
      return new (zone_) FunctionLiteral(
          zone_, ast_value_factory_->empty_string(), ast_value_factory_, scope,
          body, expected_property_count, parameter_count, parameter_count,
          FunctionLiteral::kAnonymousExpression,
          FunctionLiteral::kNoDuplicateParameters,
          FunctionLiteral::kShouldLazyCompile, 0, /* has_braces */ false,
          FunctionLiteral::kIdTypeTopLevel);
    }
  
    ClassLiteral::Property* NewClassLiteralProperty(
        Expression* key, Expression* value, ClassLiteralProperty::Kind kind,
        bool is_static, bool is_computed_name, bool is_private) {
      return new (zone_) ClassLiteral::Property(key, value, kind, is_static,
                                                is_computed_name, is_private);
    }
  
    ClassLiteral* NewClassLiteral(
        Scope* scope, Variable* variable, Expression* extends,
        FunctionLiteral* constructor,
        ZonePtrList<ClassLiteral::Property>* properties,
        FunctionLiteral* static_fields_initializer,
        FunctionLiteral* instance_members_initializer_function,
        int start_position, int end_position, bool has_name_static_property,
        bool has_static_computed_names, bool is_anonymous) {
      return new (zone_) ClassLiteral(
          scope, variable, extends, constructor, properties,
          static_fields_initializer, instance_members_initializer_function,
          start_position, end_position, has_name_static_property,
          has_static_computed_names, is_anonymous);
    }
  
    NativeFunctionLiteral* NewNativeFunctionLiteral(const AstRawString* name,
                                                    v8::Extension* extension,
                                                    int pos) {
      return new (zone_) NativeFunctionLiteral(name, extension, pos);
    }
  
    DoExpression* NewDoExpression(Block* block, Variable* result_var, int pos) {
      VariableProxy* result = NewVariableProxy(result_var, pos);
      return new (zone_) DoExpression(block, result, pos);
    }
  
    SuperPropertyReference* NewSuperPropertyReference(Expression* home_object,
                                                      int pos) {
      return new (zone_) SuperPropertyReference(home_object, pos);
    }
  
    SuperCallReference* NewSuperCallReference(VariableProxy* new_target_var,
                                              VariableProxy* this_function_var,
                                              int pos) {
      return new (zone_)
          SuperCallReference(new_target_var, this_function_var, pos);
    }
  
    EmptyParentheses* NewEmptyParentheses(int pos) {
      return new (zone_) EmptyParentheses(pos);
    }
  
    GetTemplateObject* NewGetTemplateObject(
        const ZonePtrList<const AstRawString>* cooked_strings,
        const ZonePtrList<const AstRawString>* raw_strings, int pos) {
      return new (zone_) GetTemplateObject(cooked_strings, raw_strings, pos);
    }
  
    TemplateLiteral* NewTemplateLiteral(
        const ZonePtrList<const AstRawString>* string_parts,
        const ZonePtrList<Expression>* substitutions, int pos) {
      return new (zone_) TemplateLiteral(string_parts, substitutions, pos);
    }
  
    ImportCallExpression* NewImportCallExpression(Expression* args, int pos) {
      return new (zone_) ImportCallExpression(args, pos);
    }
  
    InitializeClassMembersStatement* NewInitializeClassMembersStatement(
        ZonePtrList<ClassLiteral::Property>* args, int pos) {
      return new (zone_) InitializeClassMembersStatement(args, pos);
    }
  
    Zone* zone() const { return zone_; }
  
   private:
    // This zone may be deallocated upon returning from parsing a function body
    // which we can guarantee is not going to be compiled or have its AST
    // inspected.
    // See ParseFunctionLiteral in parser.cc for preconditions.
    Zone* zone_;
    AstValueFactory* ast_value_factory_;
    class EmptyStatement* empty_statement_;
    class ThisExpression* this_expression_;
    class FailureExpression* failure_expression_;
  };
  
  
  // Type testing & conversion functions overridden by concrete subclasses.
  // Inline functions for AstNode.
  
  #define DECLARE_NODE_FUNCTIONS(type)                                         \
    bool AstNode::Is##type() const { return node_type() == AstNode::k##type; } \
    type* AstNode::As##type() {                                                \
      return node_type() == AstNode::k##type ? reinterpret_cast<type*>(this)   \
                                             : nullptr;                        \
    }                                                                          \
    const type* AstNode::As##type() const {                                    \
      return node_type() == AstNode::k##type                                   \
                 ? reinterpret_cast<const type*>(this)                         \
                 : nullptr;                                                    \
    }
  AST_NODE_LIST(DECLARE_NODE_FUNCTIONS)
  FAILURE_NODE_LIST(DECLARE_NODE_FUNCTIONS)
  #undef DECLARE_NODE_FUNCTIONS
  
  }  // namespace internal
  }  // namespace v8
  
  #endif  // V8_AST_AST_H_
  