// Copyright 2018 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.

#include "src/torque/torque-parser.h"

#include <algorithm>
#include <cctype>
#include <set>
#include <stdexcept>
#include <unordered_map>

#include "src/flags/flags.h"
#include "src/torque/ast.h"
#include "src/torque/constants.h"
#include "src/torque/declarations.h"
#include "src/torque/earley-parser.h"
#include "src/torque/utils.h"

namespace v8 {
namespace internal {
namespace torque {

DEFINE_CONTEXTUAL_VARIABLE(CurrentAst)

using TypeList = std::vector<TypeExpression*>;

struct ExpressionWithSource {
  Expression* expression;
  std::string source;
};

struct TypeswitchCase {
  SourcePosition pos;
  base::Optional<Identifier*> name;
  TypeExpression* type;
  Statement* block;
};

struct EnumEntry {
  Identifier* name;
  base::Optional<TypeExpression*> type;
};

class BuildFlags : public ContextualClass<BuildFlags> {
 public:
  BuildFlags() {
    build_flags_["V8_SFI_HAS_UNIQUE_ID"] = V8_SFI_HAS_UNIQUE_ID;
    build_flags_["V8_EXTERNAL_CODE_SPACE"] = V8_EXTERNAL_CODE_SPACE_BOOL;
    build_flags_["TAGGED_SIZE_8_BYTES"] = TAGGED_SIZE_8_BYTES;
    build_flags_["TRUE_FOR_TESTING"] = true;
    build_flags_["FALSE_FOR_TESTING"] = false;
  }
  static bool GetFlag(const std::string& name, const char* production) {
    auto it = Get().build_flags_.find(name);
    if (it == Get().build_flags_.end()) {
      ReportError("Unknown flag used in ", production, ": ", name,
                  ". Please add it to the list in BuildFlags.");
    }
    return it->second;
  }

 private:
  std::unordered_map<std::string, bool> build_flags_;
};
DEFINE_CONTEXTUAL_VARIABLE(BuildFlags)

template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<std::string>::id =
    ParseResultTypeId::kStdString;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<bool>::id =
    ParseResultTypeId::kBool;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<int32_t>::id =
    ParseResultTypeId::kInt32;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<std::string>>::id =
        ParseResultTypeId::kStdVectorOfString;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Declaration*>::id =
    ParseResultTypeId::kDeclarationPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<TypeExpression*>::id =
        ParseResultTypeId::kTypeExpressionPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<base::Optional<TypeExpression*>>::id =
        ParseResultTypeId::kOptionalTypeExpressionPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<TryHandler*>::id =
    ParseResultTypeId::kTryHandlerPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Expression*>::id =
    ParseResultTypeId::kExpressionPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Identifier*>::id =
    ParseResultTypeId::kIdentifierPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<base::Optional<Identifier*>>::id =
        ParseResultTypeId::kOptionalIdentifierPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Statement*>::id =
    ParseResultTypeId::kStatementPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<NameAndTypeExpression>::id =
        ParseResultTypeId::kNameAndTypeExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<EnumEntry>::id =
    ParseResultTypeId::kEnumEntry;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<EnumEntry>>::id =
        ParseResultTypeId::kStdVectorOfEnumEntry;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<NameAndExpression>::id =
        ParseResultTypeId::kNameAndExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<Annotation>::id =
    ParseResultTypeId::kAnnotation;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<Annotation>>::id =
        ParseResultTypeId::kVectorOfAnnotation;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<AnnotationParameter>::id =
        ParseResultTypeId::kAnnotationParameter;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<base::Optional<AnnotationParameter>>::id =
        ParseResultTypeId::kOptionalAnnotationParameter;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<ClassFieldExpression>::id =
        ParseResultTypeId::kClassFieldExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<StructFieldExpression>::id =
        ParseResultTypeId::kStructFieldExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<BitFieldDeclaration>::id =
        ParseResultTypeId::kBitFieldDeclaration;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<NameAndTypeExpression>>::id =
        ParseResultTypeId::kStdVectorOfNameAndTypeExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<ImplicitParameters>::id =
        ParseResultTypeId::kImplicitParameters;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<base::Optional<ImplicitParameters>>::id =
        ParseResultTypeId::kOptionalImplicitParameters;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<NameAndExpression>>::id =
        ParseResultTypeId::kStdVectorOfNameAndExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<ClassFieldExpression>>::id =
        ParseResultTypeId::kStdVectorOfClassFieldExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<StructFieldExpression>>::id =
        ParseResultTypeId::kStdVectorOfStructFieldExpression;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<BitFieldDeclaration>>::id =
        ParseResultTypeId::kStdVectorOfBitFieldDeclaration;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<IncrementDecrementOperator>::id =
        ParseResultTypeId::kIncrementDecrementOperator;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<base::Optional<std::string>>::id =
        ParseResultTypeId::kOptionalStdString;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<Statement*>>::id =
        ParseResultTypeId::kStdVectorOfStatementPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<Declaration*>>::id =
        ParseResultTypeId::kStdVectorOfDeclarationPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<std::vector<Declaration*>>>::id =
        ParseResultTypeId::kStdVectorOfStdVectorOfDeclarationPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<Expression*>>::id =
        ParseResultTypeId::kStdVectorOfExpressionPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<ExpressionWithSource>::id =
        ParseResultTypeId::kExpressionWithSource;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<ParameterList>::id =
    ParseResultTypeId::kParameterList;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<TypeList>::id =
    ParseResultTypeId::kTypeList;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<base::Optional<TypeList>>::id =
        ParseResultTypeId::kOptionalTypeList;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<LabelAndTypes>::id =
    ParseResultTypeId::kLabelAndTypes;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<LabelAndTypes>>::id =
        ParseResultTypeId::kStdVectorOfLabelAndTypes;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<TryHandler*>>::id =
        ParseResultTypeId::kStdVectorOfTryHandlerPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<base::Optional<Statement*>>::id =
        ParseResultTypeId::kOptionalStatementPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<base::Optional<Expression*>>::id =
        ParseResultTypeId::kOptionalExpressionPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<TypeswitchCase>::id = ParseResultTypeId::kTypeswitchCase;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<TypeswitchCase>>::id =
        ParseResultTypeId::kStdVectorOfTypeswitchCase;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<std::vector<Identifier*>>::id =
        ParseResultTypeId::kStdVectorOfIdentifierPtr;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<base::Optional<ClassBody*>>::id =
        ParseResultTypeId::kOptionalClassBody;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<GenericParameter>::id =
        ParseResultTypeId::kGenericParameter;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
    ParseResultHolder<GenericParameters>::id =
        ParseResultTypeId::kGenericParameters;

namespace {

base::Optional<ParseResult> AddGlobalDeclarations(
    ParseResultIterator* child_results) {
  auto declarations = child_results->NextAs<std::vector<Declaration*>>();
  for (Declaration* declaration : declarations) {
    CurrentAst::Get().declarations().push_back(declaration);
  }
  return base::nullopt;
}

void NamingConventionError(const std::string& type, const std::string& name,
                           const std::string& convention,
                           SourcePosition pos = CurrentSourcePosition::Get()) {
  Lint(type, " \"", name, "\" does not follow \"", convention,
       "\" naming convention.")
      .Position(pos);
}

void NamingConventionError(const std::string& type, const Identifier* name,
                           const std::string& convention) {
  NamingConventionError(type, name->value, convention, name->pos);
}

void LintGenericParameters(const GenericParameters& parameters) {
  for (auto parameter : parameters) {
    if (!IsUpperCamelCase(parameter.name->value)) {
      NamingConventionError("Generic parameter", parameter.name,
                            "UpperCamelCase");
    }
  }
}

base::Optional<ParseResult> ConcatList(ParseResultIterator* child_results) {
  auto list_of_lists =
      child_results->NextAs<std::vector<std::vector<Declaration*>>>();
  std::vector<Declaration*> result;
  for (auto& list : list_of_lists) {
    result.insert(result.end(), list.begin(), list.end());
  }
  return ParseResult{result};
}

void CheckNotDeferredStatement(Statement* statement) {
  CurrentSourcePosition::Scope source_position(statement->pos);
  if (BlockStatement* block = BlockStatement::DynamicCast(statement)) {
    if (block->deferred) {
      Lint(
          "cannot use deferred with a statement block here, it will have no "
          "effect");
    }
  }
}

TypeExpression* AddConstexpr(TypeExpression* type) {
  BasicTypeExpression* basic = BasicTypeExpression::DynamicCast(type);
  if (!basic) Error("Unsupported extends clause.").Throw();
  return MakeNode<BasicTypeExpression>(
      basic->namespace_qualification,
      MakeNode<Identifier>(CONSTEXPR_TYPE_PREFIX + basic->name->value),
      basic->generic_arguments);
}

Expression* MakeCall(IdentifierExpression* callee,
                     base::Optional<Expression*> target,
                     std::vector<Expression*> arguments,
                     const std::vector<Statement*>& otherwise) {
  std::vector<Identifier*> labels;

  // All IdentifierExpressions are treated as label names and can be directly
  // used as labels identifiers. All other statements in a call's otherwise
  // must create intermediate Labels for the otherwise's statement code.
  size_t label_id_count = 0;
  std::vector<TryHandler*> temp_labels;
  for (auto* statement : otherwise) {
    if (auto* e = ExpressionStatement::DynamicCast(statement)) {
      if (auto* id = IdentifierExpression::DynamicCast(e->expression)) {
        if (id->generic_arguments.size() != 0) {
          ReportError("An otherwise label cannot have generic parameters");
        }
        labels.push_back(id->name);
        continue;
      }
    }
    auto label_name = std::string("__label") + std::to_string(label_id_count++);
    auto label_id = MakeNode<Identifier>(label_name);
    label_id->pos = SourcePosition::Invalid();
    labels.push_back(label_id);
    auto* handler =
        MakeNode<TryHandler>(TryHandler::HandlerKind::kLabel, label_id,
                             ParameterList::Empty(), statement);
    temp_labels.push_back(handler);
  }

  // Create nested try-label expression for all of the temporary Labels that
  // were created.
  Expression* result = nullptr;
  if (target) {
    result = MakeNode<CallMethodExpression>(*target, callee, arguments, labels);
  } else {
    result = MakeNode<CallExpression>(callee, arguments, labels);
  }

  for (auto* label : temp_labels) {
    result = MakeNode<TryLabelExpression>(result, label);
  }
  return result;
}

Expression* MakeCall(Identifier* callee,
                     const std::vector<TypeExpression*>& generic_arguments,
                     const std::vector<Expression*>& arguments,
                     const std::vector<Statement*>& otherwise) {
  return MakeCall(MakeNode<IdentifierExpression>(callee, generic_arguments),
                  base::nullopt, arguments, otherwise);
}

base::Optional<ParseResult> MakeCall(ParseResultIterator* child_results) {
  auto callee = child_results->NextAs<Expression*>();
  auto args = child_results->NextAs<std::vector<Expression*>>();
  auto otherwise = child_results->NextAs<std::vector<Statement*>>();
  IdentifierExpression* target = IdentifierExpression::cast(callee);
  return ParseResult{MakeCall(target, base::nullopt, args, otherwise)};
}

base::Optional<ParseResult> MakeMethodCall(ParseResultIterator* child_results) {
  auto this_arg = child_results->NextAs<Expression*>();
  auto callee = child_results->NextAs<Identifier*>();
  auto args = child_results->NextAs<std::vector<Expression*>>();
  auto otherwise = child_results->NextAs<std::vector<Statement*>>();
  return ParseResult{MakeCall(MakeNode<IdentifierExpression>(callee), this_arg,
                              args, otherwise)};
}

base::Optional<ParseResult> MakeNewExpression(
    ParseResultIterator* child_results) {
  bool pretenured = child_results->NextAs<bool>();

  auto type = child_results->NextAs<TypeExpression*>();
  auto initializers = child_results->NextAs<std::vector<NameAndExpression>>();

  Expression* result =
      MakeNode<NewExpression>(type, std::move(initializers), pretenured);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeBinaryOperator(
    ParseResultIterator* child_results) {
  auto left = child_results->NextAs<Expression*>();
  auto op = child_results->NextAs<Identifier*>();
  auto right = child_results->NextAs<Expression*>();
  return ParseResult{MakeCall(op, TypeList{},
                              std::vector<Expression*>{left, right},
                              std::vector<Statement*>{})};
}

base::Optional<ParseResult> MakeIntrinsicCallExpression(
    ParseResultIterator* child_results) {
  auto callee = child_results->NextAs<Identifier*>();
  auto generic_arguments =
      child_results->NextAs<std::vector<TypeExpression*>>();
  auto args = child_results->NextAs<std::vector<Expression*>>();
  Expression* result =
      MakeNode<IntrinsicCallExpression>(callee, generic_arguments, args);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeUnaryOperator(
    ParseResultIterator* child_results) {
  auto op = child_results->NextAs<Identifier*>();
  auto e = child_results->NextAs<Expression*>();
  return ParseResult{MakeCall(op, TypeList{}, std::vector<Expression*>{e},
                              std::vector<Statement*>{})};
}

base::Optional<ParseResult> MakeSpreadExpression(
    ParseResultIterator* child_results) {
  auto spreadee = child_results->NextAs<Expression*>();
  Expression* result = MakeNode<SpreadExpression>(spreadee);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeImplicitParameterList(
    ParseResultIterator* child_results) {
  auto kind = child_results->NextAs<Identifier*>();
  auto parameters = child_results->NextAs<std::vector<NameAndTypeExpression>>();
  return ParseResult{ImplicitParameters{kind, parameters}};
}

void AddParameter(ParameterList* parameter_list,
                  const NameAndTypeExpression& param) {
  if (!IsLowerCamelCase(param.name->value)) {
    NamingConventionError("Parameter", param.name, "lowerCamelCase");
  }
  parameter_list->names.push_back(param.name);
  parameter_list->types.push_back(param.type);
}

template <bool has_varargs, bool has_explicit_parameter_names>
base::Optional<ParseResult> MakeParameterList(
    ParseResultIterator* child_results) {
  auto implicit_params =
      child_results->NextAs<base::Optional<ImplicitParameters>>();
  ParameterList result;
  result.has_varargs = has_varargs;
  result.implicit_count = 0;
  result.implicit_kind = ImplicitKind::kNoImplicit;
  if (implicit_params) {
    result.implicit_count = implicit_params->parameters.size();
    if (implicit_params->kind->value == "implicit") {
      result.implicit_kind = ImplicitKind::kImplicit;
    } else {
      DCHECK_EQ(implicit_params->kind->value, "js-implicit");
      result.implicit_kind = ImplicitKind::kJSImplicit;
    }
    result.implicit_kind_pos = implicit_params->kind->pos;
    for (NameAndTypeExpression& implicit_param : implicit_params->parameters) {
      AddParameter(&result, implicit_param);
    }
  }
  if (has_explicit_parameter_names) {
    auto explicit_params =
        child_results->NextAs<std::vector<NameAndTypeExpression>>();
    std::string arguments_variable = "";
    if (has_varargs) {
      arguments_variable = child_results->NextAs<std::string>();
    }
    for (NameAndTypeExpression& param : explicit_params) {
      AddParameter(&result, param);
    }
    result.arguments_variable = arguments_variable;
  } else {
    auto explicit_types = child_results->NextAs<TypeList>();
    for (auto* explicit_type : explicit_types) {
      result.types.push_back(explicit_type);
    }
  }
  return ParseResult{std::move(result)};
}

base::Optional<ParseResult> MakeAssertStatement(
    ParseResultIterator* child_results) {
  auto kind_string = child_results->NextAs<Identifier*>()->value;
  auto expr_with_source = child_results->NextAs<ExpressionWithSource>();
  AssertStatement::AssertKind kind;
  if (kind_string == "dcheck") {
    kind = AssertStatement::AssertKind::kDcheck;
  } else if (kind_string == "check") {
    kind = AssertStatement::AssertKind::kCheck;
  } else if (kind_string == "static_assert") {
    kind = AssertStatement::AssertKind::kStaticAssert;
  } else {
    UNREACHABLE();
  }
  Statement* result = MakeNode<AssertStatement>(
      kind, expr_with_source.expression, expr_with_source.source);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeDebugStatement(
    ParseResultIterator* child_results) {
  auto kind = child_results->NextAs<Identifier*>()->value;
  DCHECK(kind == "unreachable" || kind == "debug");
  Statement* result = MakeNode<DebugStatement>(kind, kind == "unreachable");
  return ParseResult{result};
}

base::Optional<ParseResult> DeprecatedMakeVoidType(
    ParseResultIterator* child_results) {
  Error("Default void return types are deprecated. Add `: void`.");
  TypeExpression* result = MakeNode<BasicTypeExpression>(
      std::vector<std::string>{}, MakeNode<Identifier>("void"),
      std::vector<TypeExpression*>{});
  return ParseResult{result};
}

base::Optional<ParseResult> MakeExternalMacro(
    ParseResultIterator* child_results) {
  auto transitioning = child_results->NextAs<bool>();
  auto operator_name = child_results->NextAs<base::Optional<std::string>>();
  auto external_assembler_name =
      child_results->NextAs<base::Optional<std::string>>();
  auto name = child_results->NextAs<Identifier*>();
  auto generic_parameters = child_results->NextAs<GenericParameters>();
  LintGenericParameters(generic_parameters);

  auto args = child_results->NextAs<ParameterList>();
  auto return_type = child_results->NextAs<TypeExpression*>();
  auto labels = child_results->NextAs<LabelAndTypesVector>();

  Declaration* result = MakeNode<ExternalMacroDeclaration>(
      transitioning,
      external_assembler_name ? *external_assembler_name : "CodeStubAssembler",
      name, operator_name, args, return_type, labels);
  if (!generic_parameters.empty()) {
    Error("External builtins cannot be generic.");
  }
  return ParseResult{result};
}

base::Optional<ParseResult> MakeIntrinsicDeclaration(
    ParseResultIterator* child_results) {
  auto name = child_results->NextAs<Identifier*>();
  auto generic_parameters = child_results->NextAs<GenericParameters>();
  LintGenericParameters(generic_parameters);

  auto args = child_results->NextAs<ParameterList>();
  auto return_type = child_results->NextAs<TypeExpression*>();
  auto body = child_results->NextAs<base::Optional<Statement*>>();
  LabelAndTypesVector labels;
  CallableDeclaration* declaration;
  if (body) {
    declaration = MakeNode<TorqueMacroDeclaration>(
        false, name, base::Optional<std::string>{}, args, return_type, labels,
        false, body);
  } else {
    declaration = MakeNode<IntrinsicDeclaration>(name, args, return_type);
  }
  Declaration* result = declaration;
  if (!generic_parameters.empty()) {
    result =
        MakeNode<GenericCallableDeclaration>(generic_parameters, declaration);
  }
  return ParseResult{result};
}

namespace {
bool HasAnnotation(ParseResultIterator* child_results, const char* annotation,
                   const char* declaration) {
  auto annotations = child_results->NextAs<std::vector<Annotation>>();
  if (annotations.size()) {
    if (annotations.size() > 1 || annotations[0].name->value != annotation) {
      Error(declaration, " declarations only support a single ", annotation,
            " annotation");
    }
    return true;
  }
  return false;
}

bool HasExportAnnotation(ParseResultIterator* child_results,
                         const char* declaration) {
  return HasAnnotation(child_results, ANNOTATION_EXPORT, declaration);
}
}  // namespace

base::Optional<ParseResult> MakeTorqueMacroDeclaration(
    ParseResultIterator* child_results) {
  bool export_to_csa = HasExportAnnotation(child_results, "macro");
  auto transitioning = child_results->NextAs<bool>();
  auto operator_name = child_results->NextAs<base::Optional<std::string>>();
  auto name = child_results->NextAs<Identifier*>();
  if (!IsUpperCamelCase(name->value)) {
    NamingConventionError("Macro", name, "UpperCamelCase");
  }

  auto generic_parameters = child_results->NextAs<GenericParameters>();
  LintGenericParameters(generic_parameters);

  auto args = child_results->NextAs<ParameterList>();
  auto return_type = child_results->NextAs<TypeExpression*>();
  auto labels = child_results->NextAs<LabelAndTypesVector>();
  auto body = child_results->NextAs<base::Optional<Statement*>>();
  CallableDeclaration* declaration = MakeNode<TorqueMacroDeclaration>(
      transitioning, name, operator_name, args, return_type, labels,
      export_to_csa, body);
  Declaration* result = declaration;
  if (generic_parameters.empty()) {
    if (!body) ReportError("A non-generic declaration needs a body.");
  } else {
    if (export_to_csa) ReportError("Cannot export generics to CSA.");
    result =
        MakeNode<GenericCallableDeclaration>(generic_parameters, declaration);
  }
  return ParseResult{result};
}

base::Optional<ParseResult> MakeTorqueBuiltinDeclaration(
    ParseResultIterator* child_results) {
  auto transitioning = child_results->NextAs<bool>();
  auto javascript_linkage = child_results->NextAs<bool>();
  auto name = child_results->NextAs<Identifier*>();
  if (!IsUpperCamelCase(name->value)) {
    NamingConventionError("Builtin", name, "UpperCamelCase");
  }

  auto generic_parameters = child_results->NextAs<GenericParameters>();
  LintGenericParameters(generic_parameters);

  auto args = child_results->NextAs<ParameterList>();
  auto return_type = child_results->NextAs<TypeExpression*>();
  auto body = child_results->NextAs<base::Optional<Statement*>>();
  CallableDeclaration* declaration = MakeNode<TorqueBuiltinDeclaration>(
      transitioning, javascript_linkage, name, args, return_type, body);
  Declaration* result = declaration;
  if (generic_parameters.empty()) {
    if (!body) ReportError("A non-generic declaration needs a body.");
  } else {
    result =
        MakeNode<GenericCallableDeclaration>(generic_parameters, declaration);
  }
  return ParseResult{result};
}

base::Optional<ParseResult> MakeConstDeclaration(
    ParseResultIterator* child_results) {
  auto name = child_results->NextAs<Identifier*>();
  if (!IsValidNamespaceConstName(name->value)) {
    NamingConventionError("Constant", name, "kUpperCamelCase");
  }

  auto type = child_results->NextAs<TypeExpression*>();
  auto expression = child_results->NextAs<Expression*>();
  Declaration* result = MakeNode<ConstDeclaration>(name, type, expression);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeExternConstDeclaration(
    ParseResultIterator* child_results) {
  auto name = child_results->NextAs<Identifier*>();
  auto type = child_results->NextAs<TypeExpression*>();
  auto literal = child_results->NextAs<std::string>();
  Declaration* result =
      MakeNode<ExternConstDeclaration>(name, type, std::move(literal));
  return ParseResult{result};
}

base::Optional<ParseResult> MakeTypeAliasDeclaration(
    ParseResultIterator* child_results) {
  auto name = child_results->NextAs<Identifier*>();
  auto type = child_results->NextAs<TypeExpression*>();
  Declaration* result = MakeNode<TypeAliasDeclaration>(name, type);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeAbstractTypeDeclaration(
    ParseResultIterator* child_results) {
  bool use_parent_type_checker = HasAnnotation(
      child_results, ANNOTATION_USE_PARENT_TYPE_CHECKER, "abstract type");
  auto transient = child_results->NextAs<bool>();
  auto name = child_results->NextAs<Identifier*>();
  if (!IsValidTypeName(name->value)) {
    NamingConventionError("Type", name, "UpperCamelCase");
  }
  auto generic_parameters = child_results->NextAs<GenericParameters>();
  auto extends = child_results->NextAs<base::Optional<TypeExpression*>>();
  auto generates = child_results->NextAs<base::Optional<std::string>>();
  AbstractTypeFlags flags(AbstractTypeFlag::kNone);
  if (transient) flags |= AbstractTypeFlag::kTransient;
  if (use_parent_type_checker) flags |= AbstractTypeFlag::kUseParentTypeChecker;
  TypeDeclaration* type_decl = MakeNode<AbstractTypeDeclaration>(
      name, flags, extends, std::move(generates));
  Declaration* decl = type_decl;
  if (!generic_parameters.empty()) {
    decl = MakeNode<GenericTypeDeclaration>(generic_parameters, type_decl);
  }

  auto constexpr_generates =
      child_results->NextAs<base::Optional<std::string>>();
  std::vector<Declaration*> result{decl};

  if (constexpr_generates) {
    // Create a AbstractTypeDeclaration for the associated constexpr type.
    Identifier* constexpr_name =
        MakeNode<Identifier>(CONSTEXPR_TYPE_PREFIX + name->value);
    constexpr_name->pos = name->pos;

    base::Optional<TypeExpression*> constexpr_extends;
    if (extends) {
      constexpr_extends = AddConstexpr(*extends);
    }
    TypeDeclaration* constexpr_decl = MakeNode<AbstractTypeDeclaration>(
        constexpr_name, flags | AbstractTypeFlag::kConstexpr, constexpr_extends,
        constexpr_generates);
    constexpr_decl->pos = name->pos;
    decl = constexpr_decl;
    if (!generic_parameters.empty()) {
      decl =
          MakeNode<GenericTypeDeclaration>(generic_parameters, constexpr_decl);
    }
    result.push_back(decl);
  }

  return ParseResult{result};
}

base::Optional<ParseResult> MakeMethodDeclaration(
    ParseResultIterator* child_results) {
  auto transitioning = child_results->NextAs<bool>();
  auto operator_name = child_results->NextAs<base::Optional<std::string>>();
  auto name = child_results->NextAs<Identifier*>();
  if (!IsUpperCamelCase(name->value)) {
    NamingConventionError("Method", name, "UpperCamelCase");
  }

  auto args = child_results->NextAs<ParameterList>();
  auto return_type = child_results->NextAs<TypeExpression*>();
  auto labels = child_results->NextAs<LabelAndTypesVector>();
  auto body = child_results->NextAs<Statement*>();
  Declaration* result =
      MakeNode<TorqueMacroDeclaration>(transitioning, name, operator_name, args,
                                       return_type, labels, false, body);
  return ParseResult{result};
}

class AnnotationSet {
 public:
  AnnotationSet(ParseResultIterator* iter,
                const std::set<std::string>& allowed_without_param,
                const std::set<std::string>& allowed_with_param) {
    auto list = iter->NextAs<std::vector<Annotation>>();
    for (const Annotation& a : list) {
      if (a.param.has_value()) {
        if (allowed_with_param.find(a.name->value) ==
            allowed_with_param.end()) {
          const char* error_message =
              allowed_without_param.find(a.name->value) ==
                      allowed_without_param.end()
                  ? " is not allowed here"
                  : " cannot have parameter here";
          Lint("Annotation ", a.name->value, error_message)
              .Position(a.name->pos);
        }
        if (!map_.insert({a.name->value, {*a.param, a.name->pos}}).second) {
          Lint("Duplicate annotation ", a.name->value).Position(a.name->pos);
        }
      } else {
        if (allowed_without_param.find(a.name->value) ==
            allowed_without_param.end()) {
          const char* error_message =
              allowed_with_param.find(a.name->value) == allowed_with_param.end()
                  ? " is not allowed here"
                  : " requires a parameter here";
          Lint("Annotation ", a.name->value, error_message)
              .Position(a.name->pos);
        }
        if (!set_.insert(a.name->value).second) {
          Lint("Duplicate annotation ", a.name->value).Position(a.name->pos);
        }
      }
    }
  }

  bool Contains(const std::string& s) const {
    return set_.find(s) != set_.end();
  }
  base::Optional<std::string> GetStringParam(const std::string& s) const {
    auto it = map_.find(s);
    if (it == map_.end()) {
      return {};
    }
    if (it->second.first.is_int) {
      Error("Annotation ", s, " requires a string parameter but has an int")
          .Position(it->second.second);
    }
    return it->second.first.string_value;
  }
  base::Optional<int32_t> GetIntParam(const std::string& s) const {
    auto it = map_.find(s);
    if (it == map_.end()) {
      return {};
    }
    if (!it->second.first.is_int) {
      Error("Annotation ", s, " requires an int parameter but has a string")
          .Position(it->second.second);
    }
    return it->second.first.int_value;
  }

 private:
  std::set<std::string> set_;
  std::map<std::string, std::pair<AnnotationParameter, SourcePosition>> map_;
};

base::Optional<ParseResult> MakeInt32(ParseResultIterator* child_results) {
  std::string value = child_results->NextAs<std::string>();
  size_t num_chars_converted = 0;
  int result = 0;
  try {
    result = std::stoi(value, &num_chars_converted, 0);
  } catch (const std::invalid_argument&) {
    Error("Expected an integer");
    return ParseResult{result};
  } catch (const std::out_of_range&) {
    Error("Integer out of 32-bit range");
    return ParseResult{result};
  }
  // Tokenizer shouldn't have included extra trailing characters.
  DCHECK_EQ(num_chars_converted, value.size());
  return ParseResult{result};
}

base::Optional<ParseResult> MakeStringAnnotationParameter(
    ParseResultIterator* child_results) {
  std::string value = child_results->NextAs<std::string>();
  AnnotationParameter result{value, 0, false};
  return ParseResult{result};
}

base::Optional<ParseResult> MakeIntAnnotationParameter(
    ParseResultIterator* child_results) {
  int32_t value = child_results->NextAs<int32_t>();
  AnnotationParameter result{"", value, true};
  return ParseResult{result};
}

int GetAnnotationValue(const AnnotationSet& annotations, const char* name,
                       int default_value) {
  auto opt_value = annotations.GetIntParam(name);
  return opt_value.has_value() ? *opt_value : default_value;
}

InstanceTypeConstraints MakeInstanceTypeConstraints(
    const AnnotationSet& annotations) {
  InstanceTypeConstraints result;
  result.value =
      GetAnnotationValue(annotations, ANNOTATION_INSTANCE_TYPE_VALUE, -1);
  result.num_flags_bits = GetAnnotationValue(
      annotations, ANNOTATION_RESERVE_BITS_IN_INSTANCE_TYPE, -1);
  return result;
}

base::Optional<ParseResult> MakeClassBody(ParseResultIterator* child_results) {
  auto methods = child_results->NextAs<std::vector<Declaration*>>();
  auto fields = child_results->NextAs<std::vector<ClassFieldExpression>>();
  base::Optional<ClassBody*> result =
      MakeNode<ClassBody>(std::move(methods), std::move(fields));
  return ParseResult(result);
}

base::Optional<ParseResult> MakeClassDeclaration(
    ParseResultIterator* child_results) {
  AnnotationSet annotations(
      child_results,
      {ANNOTATION_ABSTRACT, ANNOTATION_HAS_SAME_INSTANCE_TYPE_AS_PARENT,
       ANNOTATION_DO_NOT_GENERATE_CPP_CLASS, ANNOTATION_CUSTOM_CPP_CLASS,
       ANNOTATION_CUSTOM_MAP, ANNOTATION_GENERATE_BODY_DESCRIPTOR,
       ANNOTATION_EXPORT, ANNOTATION_DO_NOT_GENERATE_CAST,
       ANNOTATION_HIGHEST_INSTANCE_TYPE_WITHIN_PARENT,
       ANNOTATION_LOWEST_INSTANCE_TYPE_WITHIN_PARENT},
      {ANNOTATION_RESERVE_BITS_IN_INSTANCE_TYPE,
       ANNOTATION_INSTANCE_TYPE_VALUE});
  ClassFlags flags = ClassFlag::kNone;
  if (annotations.Contains(ANNOTATION_ABSTRACT)) {
    flags |= ClassFlag::kAbstract;
  }
  if (annotations.Contains(ANNOTATION_HAS_SAME_INSTANCE_TYPE_AS_PARENT)) {
    flags |= ClassFlag::kHasSameInstanceTypeAsParent;
  }
  bool do_not_generate_cpp_class =
      annotations.Contains(ANNOTATION_DO_NOT_GENERATE_CPP_CLASS);
  if (annotations.Contains(ANNOTATION_CUSTOM_CPP_CLASS)) {
    flags |= ClassFlag::kCustomCppClass;
  }
  if (annotations.Contains(ANNOTATION_CUSTOM_MAP)) {
    flags |= ClassFlag::kCustomMap;
  }
  if (annotations.Contains(ANNOTATION_DO_NOT_GENERATE_CAST)) {
    flags |= ClassFlag::kDoNotGenerateCast;
  }
  if (annotations.Contains(ANNOTATION_GENERATE_BODY_DESCRIPTOR)) {
    flags |= ClassFlag::kGenerateBodyDescriptor;
  }
  if (annotations.Contains(ANNOTATION_EXPORT)) {
    flags |= ClassFlag::kExport;
  }
  if (annotations.Contains(ANNOTATION_HIGHEST_INSTANCE_TYPE_WITHIN_PARENT)) {
    flags |= ClassFlag::kHighestInstanceTypeWithinParent;
  }
  if (annotations.Contains(ANNOTATION_LOWEST_INSTANCE_TYPE_WITHIN_PARENT)) {
    flags |= ClassFlag::kLowestInstanceTypeWithinParent;
  }

  auto is_extern = child_results->NextAs<bool>();
  if (is_extern) flags |= ClassFlag::kExtern;
  auto transient = child_results->NextAs<bool>();
  if (transient) flags |= ClassFlag::kTransient;
  std::string kind = child_results->NextAs<Identifier*>()->value;
  if (kind == "shape") {
    flags |= ClassFlag::kIsShape;
    flags |= ClassFlag::kTransient;
    flags |= ClassFlag::kHasSameInstanceTypeAsParent;
    flags |= ClassFlag::kDoNotGenerateCast;
  } else {
    DCHECK_EQ(kind, "class");
  }
  auto name = child_results->NextAs<Identifier*>();
  if (!IsValidTypeName(name->value)) {
    NamingConventionError("Type", name, "UpperCamelCase");
  }
  auto extends = child_results->NextAs<TypeExpression*>();
  if (!BasicTypeExpression::DynamicCast(extends)) {
    ReportError("Expected type name in extends clause.");
  }
  auto generates = child_results->NextAs<base::Optional<std::string>>();
  auto body = child_results->NextAs<base::Optional<ClassBody*>>();
  std::vector<Declaration*> methods;
  std::vector<ClassFieldExpression> fields_raw;
  if (body.has_value()) {
    methods = (*body)->methods;
    fields_raw = (*body)->fields;
  } else {
    flags |= ClassFlag::kUndefinedLayout;
  }

  if (is_extern && body.has_value()) {
    if (!do_not_generate_cpp_class) {
      flags |= ClassFlag::kGenerateCppClassDefinitions;
    }
  } else if (do_not_generate_cpp_class) {
    Lint("Annotation @doNotGenerateCppClass has no effect");
  }

  // Filter to only include fields that should be present based on decoration.
  std::vector<ClassFieldExpression> fields;
  std::copy_if(
      fields_raw.begin(), fields_raw.end(), std::back_inserter(fields),
      [](const ClassFieldExpression& exp) {
        for (const ConditionalAnnotation& condition : exp.conditions) {
          if (condition.type == ConditionalAnnotationType::kPositive
                  ? !BuildFlags::GetFlag(condition.condition, ANNOTATION_IF)
                  : BuildFlags::GetFlag(condition.condition,
                                        ANNOTATION_IFNOT)) {
            return false;
          }
        }
        return true;
      });

  std::vector<Declaration*> result;

  result.push_back(MakeNode<ClassDeclaration>(
      name, flags, extends, generates, std::move(methods), fields,
      MakeInstanceTypeConstraints(annotations)));

  Identifier* constexpr_name =
      MakeNode<Identifier>(CONSTEXPR_TYPE_PREFIX + name->value);
  constexpr_name->pos = name->pos;
  TypeExpression* constexpr_extends = AddConstexpr(extends);
  AbstractTypeFlags abstract_type_flags(AbstractTypeFlag::kConstexpr);
  if (transient) abstract_type_flags |= AbstractTypeFlag::kTransient;
  TypeDeclaration* constexpr_decl = MakeNode<AbstractTypeDeclaration>(
      constexpr_name, abstract_type_flags, constexpr_extends,
      generates ? UnwrapTNodeTypeName(*generates) : name->value);
  constexpr_decl->pos = name->pos;
  result.push_back(constexpr_decl);

  if ((flags & ClassFlag::kDoNotGenerateCast) == 0 &&
      (flags & ClassFlag::kIsShape) == 0) {
    ParameterList parameters;
    parameters.names.push_back(MakeNode<Identifier>("obj"));
    parameters.types.push_back(MakeNode<BasicTypeExpression>(
        std::vector<std::string>{}, MakeNode<Identifier>("HeapObject"),
        std::vector<TypeExpression*>{}));
    LabelAndTypesVector labels;
    labels.push_back(LabelAndTypes{MakeNode<Identifier>("CastError"),
                                   std::vector<TypeExpression*>{}});

    TypeExpression* class_type = MakeNode<BasicTypeExpression>(
        std::vector<std::string>{}, name, std::vector<TypeExpression*>{});

    std::vector<std::string> namespace_qualification{
        TORQUE_INTERNAL_NAMESPACE_STRING};

    IdentifierExpression* internal_downcast_target =
        MakeNode<IdentifierExpression>(
            namespace_qualification,
            MakeNode<Identifier>("DownCastForTorqueClass"),
            std::vector<TypeExpression*>{class_type});
    IdentifierExpression* internal_downcast_otherwise =
        MakeNode<IdentifierExpression>(std::vector<std::string>{},
                                       MakeNode<Identifier>("CastError"));

    Expression* argument = MakeNode<IdentifierExpression>(
        std::vector<std::string>{}, MakeNode<Identifier>("obj"));

    auto value = MakeCall(internal_downcast_target, base::nullopt,
                          std::vector<Expression*>{argument},
                          std::vector<Statement*>{MakeNode<ExpressionStatement>(
                              internal_downcast_otherwise)});

    auto cast_body = MakeNode<ReturnStatement>(value);

    std::vector<TypeExpression*> generic_parameters;
    generic_parameters.push_back(MakeNode<BasicTypeExpression>(
        std::vector<std::string>{}, name, std::vector<TypeExpression*>{}));

    Declaration* specialization = MakeNode<SpecializationDeclaration>(
        false, MakeNode<Identifier>("Cast"), generic_parameters,
        std::move(parameters), class_type, std::move(labels), cast_body);
    result.push_back(specialization);
  }

  return ParseResult{result};
}

base::Optional<ParseResult> MakeNamespaceDeclaration(
    ParseResultIterator* child_results) {
  auto name = child_results->NextAs<std::string>();
  if (!IsSnakeCase(name)) {
    NamingConventionError("Namespace", name, "snake_case");
  }
  auto declarations = child_results->NextAs<std::vector<Declaration*>>();
  Declaration* result =
      MakeNode<NamespaceDeclaration>(std::move(name), std::move(declarations));
  return ParseResult{result};
}

base::Optional<ParseResult> MakeSpecializationDeclaration(
    ParseResultIterator* child_results) {
  auto transitioning = child_results->NextAs<bool>();
  auto name = child_results->NextAs<Identifier*>();
  auto generic_parameters =
      child_results->NextAs<std::vector<TypeExpression*>>();
  auto parameters = child_results->NextAs<ParameterList>();
  auto return_type = child_results->NextAs<TypeExpression*>();
  auto labels = child_results->NextAs<LabelAndTypesVector>();
  auto body = child_results->NextAs<Statement*>();
  CheckNotDeferredStatement(body);
  Declaration* result = MakeNode<SpecializationDeclaration>(
      transitioning, std::move(name), std::move(generic_parameters),
      std::move(parameters), return_type, std::move(labels), body);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeStructDeclaration(
    ParseResultIterator* child_results) {
  bool is_export = HasExportAnnotation(child_results, "Struct");

  StructFlags flags = StructFlag::kNone;
  if (is_export) flags |= StructFlag::kExport;

  auto name = child_results->NextAs<Identifier*>();
  if (!IsValidTypeName(name->value)) {
    NamingConventionError("Struct", name, "UpperCamelCase");
  }
  auto generic_parameters = child_results->NextAs<GenericParameters>();
  LintGenericParameters(generic_parameters);
  auto methods = child_results->NextAs<std::vector<Declaration*>>();
  auto fields = child_results->NextAs<std::vector<StructFieldExpression>>();
  TypeDeclaration* struct_decl = MakeNode<StructDeclaration>(
      flags, name, std::move(methods), std::move(fields));
  Declaration* result = struct_decl;
  if (!generic_parameters.empty()) {
    result = MakeNode<GenericTypeDeclaration>(generic_parameters, struct_decl);
  }
  return ParseResult{result};
}

base::Optional<ParseResult> MakeBitFieldStructDeclaration(
    ParseResultIterator* child_results) {
  auto name = child_results->NextAs<Identifier*>();
  if (!IsValidTypeName(name->value)) {
    NamingConventionError("Bitfield struct", name, "UpperCamelCase");
  }
  auto extends = child_results->NextAs<TypeExpression*>();
  auto fields = child_results->NextAs<std::vector<BitFieldDeclaration>>();
  Declaration* decl =
      MakeNode<BitFieldStructDeclaration>(name, extends, std::move(fields));
  return ParseResult{decl};
}

base::Optional<ParseResult> MakeCppIncludeDeclaration(
    ParseResultIterator* child_results) {
  auto include_path = child_results->NextAs<std::string>();
  Declaration* result =
      MakeNode<CppIncludeDeclaration>(std::move(include_path));
  return ParseResult{result};
}

base::Optional<ParseResult> ProcessTorqueImportDeclaration(
    ParseResultIterator* child_results) {
  auto import_path = child_results->NextAs<std::string>();
  if (!SourceFileMap::FileRelativeToV8RootExists(import_path)) {
    Error("File '", import_path, "' not found.");
  }

  auto import_id = SourceFileMap::GetSourceId(import_path);
  if (!import_id.IsValid()) {
    // TODO(szuend): Instead of reporting and error. Queue the file up
    //               for compilation.
    Error("File '", import_path, "'is not part of the source set.").Throw();
  }

  CurrentAst::Get().DeclareImportForCurrentFile(import_id);

  return base::nullopt;
}

base::Optional<ParseResult> MakeExternalBuiltin(
    ParseResultIterator* child_results) {
  auto transitioning = child_results->NextAs<bool>();
  auto js_linkage = child_results->NextAs<bool>();
  auto name = child_results->NextAs<Identifier*>();
  auto generic_parameters = child_results->NextAs<GenericParameters>();
  LintGenericParameters(generic_parameters);

  auto args = child_results->NextAs<ParameterList>();
  auto return_type = child_results->NextAs<TypeExpression*>();
  Declaration* result = MakeNode<ExternalBuiltinDeclaration>(
      transitioning, js_linkage, name, args, return_type);
  if (!generic_parameters.empty()) {
    Error("External builtins cannot be generic.");
  }
  return ParseResult{result};
}

base::Optional<ParseResult> MakeExternalRuntime(
    ParseResultIterator* child_results) {
  auto transitioning = child_results->NextAs<bool>();
  auto name = child_results->NextAs<Identifier*>();
  auto args = child_results->NextAs<ParameterList>();
  auto return_type = child_results->NextAs<TypeExpression*>();
  Declaration* result = MakeNode<ExternalRuntimeDeclaration>(
      transitioning, name, args, return_type);
  return ParseResult{result};
}

base::Optional<ParseResult> StringLiteralUnquoteAction(
    ParseResultIterator* child_results) {
  return ParseResult{
      StringLiteralUnquote(child_results->NextAs<std::string>())};
}

base::Optional<ParseResult> MakeBasicTypeExpression(
    ParseResultIterator* child_results) {
  auto namespace_qualification =
      child_results->NextAs<std::vector<std::string>>();
  auto is_constexpr = child_results->NextAs<bool>();
  auto name = child_results->NextAs<std::string>();
  auto generic_arguments =
      child_results->NextAs<std::vector<TypeExpression*>>();
  TypeExpression* result = MakeNode<BasicTypeExpression>(
      std::move(namespace_qualification),
      MakeNode<Identifier>(is_constexpr ? GetConstexprName(name)
                                        : std::move(name)),
      std::move(generic_arguments));
  return ParseResult{result};
}

base::Optional<ParseResult> MakeFunctionTypeExpression(
    ParseResultIterator* child_results) {
  auto parameters = child_results->NextAs<std::vector<TypeExpression*>>();
  auto return_type = child_results->NextAs<TypeExpression*>();
  TypeExpression* result =
      MakeNode<FunctionTypeExpression>(std::move(parameters), return_type);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeReferenceTypeExpression(
    ParseResultIterator* child_results) {
  auto is_const = child_results->NextAs<bool>();
  auto referenced_type = child_results->NextAs<TypeExpression*>();
  std::vector<std::string> namespace_qualification{
      TORQUE_INTERNAL_NAMESPACE_STRING};
  std::vector<TypeExpression*> generic_arguments{referenced_type};
  TypeExpression* result = MakeNode<BasicTypeExpression>(
      namespace_qualification,
      MakeNode<Identifier>(is_const ? CONST_REFERENCE_TYPE_STRING
                                    : MUTABLE_REFERENCE_TYPE_STRING),
      generic_arguments);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeUnionTypeExpression(
    ParseResultIterator* child_results) {
  auto a = child_results->NextAs<TypeExpression*>();
  auto b = child_results->NextAs<TypeExpression*>();
  TypeExpression* result = MakeNode<UnionTypeExpression>(a, b);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeGenericParameter(
    ParseResultIterator* child_results) {
  auto name = child_results->NextAs<Identifier*>();
  auto constraint = child_results->NextAs<base::Optional<TypeExpression*>>();
  return ParseResult{GenericParameter{name, constraint}};
}

base::Optional<ParseResult> MakeExpressionStatement(
    ParseResultIterator* child_results) {
  auto expression = child_results->NextAs<Expression*>();
  Statement* result = MakeNode<ExpressionStatement>(expression);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeIfStatement(
    ParseResultIterator* child_results) {
  auto is_constexpr = child_results->NextAs<bool>();
  auto condition = child_results->NextAs<Expression*>();
  auto if_true = child_results->NextAs<Statement*>();
  auto if_false = child_results->NextAs<base::Optional<Statement*>>();

  if (if_false && !(BlockStatement::DynamicCast(if_true) &&
                    (BlockStatement::DynamicCast(*if_false) ||
                     IfStatement::DynamicCast(*if_false)))) {
    ReportError("if-else statements require curly braces");
  }

  if (is_constexpr) {
    CheckNotDeferredStatement(if_true);
    if (if_false) CheckNotDeferredStatement(*if_false);
  }

  Statement* result =
      MakeNode<IfStatement>(is_constexpr, condition, if_true, if_false);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeEnumDeclaration(
    ParseResultIterator* child_results) {
  const bool is_extern = child_results->NextAs<bool>();
  auto name_identifier = child_results->NextAs<Identifier*>();
  auto name = name_identifier->value;
  auto base_type_expression =
      child_results->NextAs<base::Optional<TypeExpression*>>();
  auto constexpr_generates_opt =
      child_results->NextAs<base::Optional<std::string>>();
  auto entries = child_results->NextAs<std::vector<EnumEntry>>();
  const bool is_open = child_results->NextAs<bool>();
  CurrentSourcePosition::Scope current_source_position(
      child_results->matched_input().pos);

  if (!is_extern) {
    ReportError("non-extern enums are not supported yet");
  }

  if (!IsValidTypeName(name)) {
    NamingConventionError("Type", name, "UpperCamelCase");
  }

  if (constexpr_generates_opt && *constexpr_generates_opt == name) {
    Lint("Unnecessary 'constexpr' clause for enum ", name);
  }
  auto constexpr_generates =
      constexpr_generates_opt ? *constexpr_generates_opt : name;
  const bool generate_nonconstexpr = base_type_expression.has_value();

  std::vector<Declaration*> result;
  // Build non-constexpr types.
  if (generate_nonconstexpr) {
    DCHECK(base_type_expression.has_value());

    if (is_open) {
      // For open enumerations, we define an abstract type and inherit all
      // entries' types from that:
      //   type Enum extends Base;
      //   namespace Enum {
      //     type kEntry0 extends Enum;
      //     ...
      //     type kEntryN extends Enum;
      //   }
      auto type_decl = MakeNode<AbstractTypeDeclaration>(
          name_identifier, AbstractTypeFlag::kNone, base_type_expression,
          base::nullopt);

      TypeExpression* name_type_expression =
          MakeNode<BasicTypeExpression>(name_identifier);
      name_type_expression->pos = name_identifier->pos;

      std::vector<Declaration*> entry_decls;
      entry_decls.reserve(entries.size());
      for (const auto& entry : entries) {
        entry_decls.push_back(MakeNode<AbstractTypeDeclaration>(
            entry.name, AbstractTypeFlag::kNone,
            entry.type.value_or(name_type_expression), base::nullopt));
      }

      result.push_back(type_decl);
      result.push_back(
          MakeNode<NamespaceDeclaration>(name, std::move(entry_decls)));
    } else {
      // For closed enumerations, we define abstract types for all entries and
      // define the enumeration as a union of those:
      //   namespace Enum {
      //     type kEntry0 extends Base;
      //     ...
      //     type kEntryN extends Base;
      //   }
      //   type Enum = Enum::kEntry0 | ... | Enum::kEntryN;
      TypeExpression* union_type = nullptr;
      std::vector<Declaration*> entry_decls;
      for (const auto& entry : entries) {
        entry_decls.push_back(MakeNode<AbstractTypeDeclaration>(
            entry.name, AbstractTypeFlag::kNone,
            entry.type.value_or(*base_type_expression), base::nullopt));

        auto entry_type = MakeNode<BasicTypeExpression>(
            std::vector<std::string>{name}, entry.name,
            std::vector<TypeExpression*>{});
        if (union_type) {
          union_type = MakeNode<UnionTypeExpression>(union_type, entry_type);
        } else {
          union_type = entry_type;
        }
      }

      result.push_back(
          MakeNode<NamespaceDeclaration>(name, std::move(entry_decls)));
      result.push_back(
          MakeNode<TypeAliasDeclaration>(name_identifier, union_type));
    }
  }

  // Build constexpr types.
  {
    // The constexpr entries inherit from an abstract enumeration type:
    //   type constexpr Enum extends constexpr Base;
    //   namespace Enum {
    //     type constexpr kEntry0 extends constexpr Enum;
    //     ...
    //     type constexpr kEntry1 extends constexpr Enum;
    //   }
    Identifier* constexpr_type_identifier =
        MakeNode<Identifier>(std::string(CONSTEXPR_TYPE_PREFIX) + name);
    TypeExpression* constexpr_type_expression = MakeNode<BasicTypeExpression>(
        MakeNode<Identifier>(std::string(CONSTEXPR_TYPE_PREFIX) + name));
    base::Optional<TypeExpression*> base_constexpr_type_expression =
        base::nullopt;
    if (base_type_expression) {
      base_constexpr_type_expression = AddConstexpr(*base_type_expression);
    }
    result.push_back(MakeNode<AbstractTypeDeclaration>(
        constexpr_type_identifier, AbstractTypeFlag::kConstexpr,
        base_constexpr_type_expression, constexpr_generates));

    TypeExpression* type_expr = nullptr;
    Identifier* fromconstexpr_identifier = nullptr;
    Identifier* fromconstexpr_parameter_identifier = nullptr;
    Statement* fromconstexpr_body = nullptr;
    if (generate_nonconstexpr) {
      DCHECK(base_type_expression.has_value());
      type_expr = MakeNode<BasicTypeExpression>(std::vector<std::string>{},
                                                MakeNode<Identifier>(name),
                                                std::vector<TypeExpression*>{});

      // return %RawDownCast<Enum>(%FromConstexpr<Base>(o)))
      fromconstexpr_identifier = MakeNode<Identifier>("FromConstexpr");
      fromconstexpr_parameter_identifier = MakeNode<Identifier>("o");
      fromconstexpr_body =
          MakeNode<ReturnStatement>(MakeNode<IntrinsicCallExpression>(
              MakeNode<Identifier>("%RawDownCast"),
              std::vector<TypeExpression*>{type_expr},
              std::vector<Expression*>{MakeNode<IntrinsicCallExpression>(
                  MakeNode<Identifier>("%FromConstexpr"),
                  std::vector<TypeExpression*>{*base_type_expression},
                  std::vector<Expression*>{MakeNode<IdentifierExpression>(
                      std::vector<std::string>{},
                      fromconstexpr_parameter_identifier)})}));
    }

    EnumDescription enum_description{CurrentSourcePosition::Get(), name,
                                     constexpr_generates, is_open};
    std::vector<Declaration*> entry_decls;
    for (const auto& entry : entries) {
      const std::string entry_name = entry.name->value;
      const std::string entry_constexpr_type =
          CONSTEXPR_TYPE_PREFIX + entry_name;
      enum_description.entries.push_back(constexpr_generates +
                                         "::" + entry_name);

      entry_decls.push_back(MakeNode<AbstractTypeDeclaration>(
          MakeNode<Identifier>(entry_constexpr_type),
          AbstractTypeFlag::kConstexpr, constexpr_type_expression,
          constexpr_generates));

      bool generate_typed_constant = entry.type.has_value();
      if (generate_typed_constant) {
        // namespace Enum {
        //   const constexpr_constant_kEntry0: constexpr kEntry0 constexpr
        //   'Enum::kEntry0'; const kEntry0 = %RawDownCast<T,
        //   Base>(FromConstexpr<Enum>(constexpr_constant_kEntry0));
        // }
        if (!generate_nonconstexpr) {
          Error(
              "Enum constants with custom types require an enum with an "
              "extends clause.")
              .Position((*entry.type)->pos);
        }
        Identifier* constexpr_constant_name =
            MakeNode<Identifier>("constexpr constant " + entry_name);
        entry_decls.push_back(MakeNode<ExternConstDeclaration>(
            constexpr_constant_name,
            MakeNode<BasicTypeExpression>(
                std::vector<std::string>{},
                MakeNode<Identifier>(entry_constexpr_type),
                std::vector<TypeExpression*>{}),
            constexpr_generates + "::" + entry_name));
        entry_decls.push_back(MakeNode<ConstDeclaration>(
            entry.name, *entry.type,
            MakeNode<IntrinsicCallExpression>(
                MakeNode<Identifier>("%RawDownCast"),
                std::vector<TypeExpression*>{*entry.type,
                                             *base_type_expression},
                std::vector<Expression*>{MakeCall(
                    MakeNode<Identifier>("FromConstexpr"), {type_expr},
                    {MakeNode<IdentifierExpression>(std::vector<std::string>{},
                                                    constexpr_constant_name)},
                    {})})));
      } else {
        // namespace Enum {
        //   const kEntry0: constexpr kEntry0 constexpr 'Enum::kEntry0';
        // }
        entry_decls.push_back(MakeNode<ExternConstDeclaration>(
            entry.name,
            MakeNode<BasicTypeExpression>(
                std::vector<std::string>{},
                MakeNode<Identifier>(entry_constexpr_type),
                std::vector<TypeExpression*>{}),
            constexpr_generates + "::" + entry_name));
      }

      // FromConstexpr<Enum, Enum::constexpr kEntry0>(
      //   : Enum::constexpr kEntry0): Enum
      if (generate_nonconstexpr) {
        TypeExpression* entry_constexpr_type_expr =
            MakeNode<BasicTypeExpression>(
                std::vector<std::string>{name},
                MakeNode<Identifier>(entry_constexpr_type),
                std::vector<TypeExpression*>{});

        ParameterList parameters;
        parameters.names.push_back(fromconstexpr_parameter_identifier);
        parameters.types.push_back(entry_constexpr_type_expr);
        result.push_back(MakeNode<SpecializationDeclaration>(
            false, fromconstexpr_identifier,
            std::vector<TypeExpression*>{type_expr, entry_constexpr_type_expr},
            std::move(parameters), type_expr, LabelAndTypesVector{},
            fromconstexpr_body));
      }
    }

    result.push_back(
        MakeNode<NamespaceDeclaration>(name, std::move(entry_decls)));
    CurrentAst::Get().AddEnumDescription(std::move(enum_description));
  }

  return ParseResult{std::move(result)};
}

base::Optional<ParseResult> MakeTypeswitchStatement(
    ParseResultIterator* child_results) {
  auto expression = child_results->NextAs<Expression*>();
  auto cases = child_results->NextAs<std::vector<TypeswitchCase>>();
  CurrentSourcePosition::Scope matched_input_current_source_position(
      child_results->matched_input().pos);

  // typeswitch (expression) case (x1 : T1) {
  //   ...b1
  // } case (x2 : T2) {
  //   ...b2
  // } case (x3 : T3) {
  //   ...b3
  // }
  //
  // desugars to
  //
  // {
  //   const _value = expression;
  //   try {
  //     const x1 : T1 = cast<T1>(_value) otherwise _NextCase;
  //     ...b1
  //   } label _NextCase {
  //     try {
  //       const x2 : T2 = cast<T2>(%assume_impossible<T1>(_value));
  //       ...b2
  //     } label _NextCase {
  //       const x3 : T3 = %assume_impossible<T1|T2>(_value);
  //       ...b3
  //     }
  //   }
  // }

  BlockStatement* current_block = MakeNode<BlockStatement>();
  Statement* result = current_block;
  {
    CurrentSourcePosition::Scope current_source_position(expression->pos);
    current_block->statements.push_back(MakeNode<VarDeclarationStatement>(
        true, MakeNode<Identifier>("__value"), base::nullopt, expression));
  }

  TypeExpression* accumulated_types;
  for (size_t i = 0; i < cases.size(); ++i) {
    CurrentSourcePosition::Scope current_source_position(cases[i].pos);
    Expression* value =
        MakeNode<IdentifierExpression>(MakeNode<Identifier>("__value"));
    if (i >= 1) {
      value =
          MakeNode<AssumeTypeImpossibleExpression>(accumulated_types, value);
    }
    BlockStatement* case_block;
    if (i < cases.size() - 1) {
      value = MakeCall(MakeNode<Identifier>("Cast"),
                       std::vector<TypeExpression*>{cases[i].type},
                       std::vector<Expression*>{value},
                       std::vector<Statement*>{MakeNode<ExpressionStatement>(
                           MakeNode<IdentifierExpression>(
                               MakeNode<Identifier>(kNextCaseLabelName)))});
      case_block = MakeNode<BlockStatement>();
    } else {
      case_block = current_block;
    }
    Identifier* name =
        cases[i].name ? *cases[i].name : MakeNode<Identifier>("__case_value");
    if (cases[i].name) name = *cases[i].name;
    case_block->statements.push_back(
        MakeNode<VarDeclarationStatement>(true, name, cases[i].type, value));
    case_block->statements.push_back(cases[i].block);
    if (i < cases.size() - 1) {
      BlockStatement* next_block = MakeNode<BlockStatement>();
      current_block->statements.push_back(
          MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>(
              MakeNode<StatementExpression>(case_block),
              MakeNode<TryHandler>(TryHandler::HandlerKind::kLabel,
                                   MakeNode<Identifier>(kNextCaseLabelName),
                                   ParameterList::Empty(), next_block))));
      current_block = next_block;
    }
    accumulated_types =
        i > 0 ? MakeNode<UnionTypeExpression>(accumulated_types, cases[i].type)
              : cases[i].type;
  }
  return ParseResult{result};
}

base::Optional<ParseResult> MakeTypeswitchCase(
    ParseResultIterator* child_results) {
  auto name = child_results->NextAs<base::Optional<Identifier*>>();
  auto type = child_results->NextAs<TypeExpression*>();
  auto block = child_results->NextAs<Statement*>();
  return ParseResult{
      TypeswitchCase{child_results->matched_input().pos, name, type, block}};
}

base::Optional<ParseResult> MakeWhileStatement(
    ParseResultIterator* child_results) {
  auto condition = child_results->NextAs<Expression*>();
  auto body = child_results->NextAs<Statement*>();
  Statement* result = MakeNode<WhileStatement>(condition, body);
  CheckNotDeferredStatement(result);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeReturnStatement(
    ParseResultIterator* child_results) {
  auto value = child_results->NextAs<base::Optional<Expression*>>();
  Statement* result = MakeNode<ReturnStatement>(value);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeTailCallStatement(
    ParseResultIterator* child_results) {
  auto value = child_results->NextAs<Expression*>();
  Statement* result = MakeNode<TailCallStatement>(CallExpression::cast(value));
  return ParseResult{result};
}

base::Optional<ParseResult> MakeVarDeclarationStatement(
    ParseResultIterator* child_results) {
  auto kind = child_results->NextAs<Identifier*>();
  bool const_qualified = kind->value == "const";
  if (!const_qualified) DCHECK_EQ("let", kind->value);
  auto name = child_results->NextAs<Identifier*>();
  if (!IsLowerCamelCase(name->value)) {
    NamingConventionError("Variable", name, "lowerCamelCase");
  }

  auto type = child_results->NextAs<base::Optional<TypeExpression*>>();
  base::Optional<Expression*> initializer;
  if (child_results->HasNext())
    initializer = child_results->NextAs<Expression*>();
  if (!initializer && !type) {
    ReportError("Declaration is missing a type.");
  }
  Statement* result = MakeNode<VarDeclarationStatement>(const_qualified, name,
                                                        type, initializer);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeBreakStatement(
    ParseResultIterator* child_results) {
  Statement* result = MakeNode<BreakStatement>();
  return ParseResult{result};
}

base::Optional<ParseResult> MakeContinueStatement(
    ParseResultIterator* child_results) {
  Statement* result = MakeNode<ContinueStatement>();
  return ParseResult{result};
}

base::Optional<ParseResult> MakeGotoStatement(
    ParseResultIterator* child_results) {
  auto label = child_results->NextAs<Identifier*>();
  auto arguments = child_results->NextAs<std::vector<Expression*>>();
  Statement* result = MakeNode<GotoStatement>(label, std::move(arguments));
  return ParseResult{result};
}

base::Optional<ParseResult> MakeBlockStatement(
    ParseResultIterator* child_results) {
  auto deferred = child_results->NextAs<bool>();
  auto statements = child_results->NextAs<std::vector<Statement*>>();
  for (Statement* statement : statements) {
    CheckNotDeferredStatement(statement);
  }
  Statement* result = MakeNode<BlockStatement>(deferred, std::move(statements));
  return ParseResult{result};
}

base::Optional<ParseResult> MakeTryLabelExpression(
    ParseResultIterator* child_results) {
  auto try_block = child_results->NextAs<Statement*>();
  CheckNotDeferredStatement(try_block);
  Statement* result = try_block;
  auto handlers = child_results->NextAs<std::vector<TryHandler*>>();
  if (handlers.empty()) {
    Error("Try blocks without catch or label don't make sense.");
  }
  for (size_t i = 0; i < handlers.size(); ++i) {
    if (i != 0 &&
        handlers[i]->handler_kind == TryHandler::HandlerKind::kCatch) {
      Error(
          "A catch handler always has to be first, before any label handler, "
          "to avoid ambiguity about whether it catches exceptions from "
          "preceding handlers or not.")
          .Position(handlers[i]->pos);
    }
    result = MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>(
        MakeNode<StatementExpression>(result), handlers[i]));
  }
  return ParseResult{result};
}

base::Optional<ParseResult> MakeForLoopStatement(
    ParseResultIterator* child_results) {
  auto var_decl = child_results->NextAs<base::Optional<Statement*>>();
  auto test = child_results->NextAs<base::Optional<Expression*>>();
  auto action = child_results->NextAs<base::Optional<Expression*>>();
  base::Optional<Statement*> action_stmt;
  if (action) action_stmt = MakeNode<ExpressionStatement>(*action);
  auto body = child_results->NextAs<Statement*>();
  CheckNotDeferredStatement(body);
  Statement* result =
      MakeNode<ForLoopStatement>(var_decl, test, action_stmt, body);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeLabelBlock(ParseResultIterator* child_results) {
  auto label = child_results->NextAs<Identifier*>();
  if (!IsUpperCamelCase(label->value)) {
    NamingConventionError("Label", label, "UpperCamelCase");
  }
  auto parameters = child_results->NextAs<ParameterList>();
  auto body = child_results->NextAs<Statement*>();
  TryHandler* result = MakeNode<TryHandler>(TryHandler::HandlerKind::kLabel,
                                            label, std::move(parameters), body);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeCatchBlock(ParseResultIterator* child_results) {
  auto variable = child_results->NextAs<std::string>();
  auto body = child_results->NextAs<Statement*>();
  if (!IsLowerCamelCase(variable)) {
    NamingConventionError("Exception", variable, "lowerCamelCase");
  }
  ParameterList parameters;
  parameters.names.push_back(MakeNode<Identifier>(variable));
  parameters.types.push_back(MakeNode<BasicTypeExpression>(
      std::vector<std::string>{}, MakeNode<Identifier>("JSAny"),
      std::vector<TypeExpression*>{}));
  parameters.has_varargs = false;
  TryHandler* result = MakeNode<TryHandler>(
      TryHandler::HandlerKind::kCatch, MakeNode<Identifier>(kCatchLabelName),
      std::move(parameters), body);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeExpressionWithSource(
    ParseResultIterator* child_results) {
  auto e = child_results->NextAs<Expression*>();
  return ParseResult{
      ExpressionWithSource{e, child_results->matched_input().ToString()}};
}

base::Optional<ParseResult> MakeIdentifier(ParseResultIterator* child_results) {
  auto name = child_results->NextAs<std::string>();
  Identifier* result = MakeNode<Identifier>(std::move(name));
  return ParseResult{result};
}

base::Optional<ParseResult> MakeIdentifierFromMatchedInput(
    ParseResultIterator* child_results) {
  return ParseResult{
      MakeNode<Identifier>(child_results->matched_input().ToString())};
}

base::Optional<ParseResult> MakeRightShiftIdentifier(
    ParseResultIterator* child_results) {
  std::string str = child_results->matched_input().ToString();
  for (auto character : str) {
    if (character != '>') {
      ReportError("right-shift operators may not contain any whitespace");
    }
  }
  return ParseResult{MakeNode<Identifier>(str)};
}

base::Optional<ParseResult> MakeNamespaceQualification(
    ParseResultIterator* child_results) {
  bool global_namespace = child_results->NextAs<bool>();
  auto namespace_qualification =
      child_results->NextAs<std::vector<std::string>>();
  if (global_namespace) {
    namespace_qualification.insert(namespace_qualification.begin(), "");
  }
  return ParseResult(std::move(namespace_qualification));
}

base::Optional<ParseResult> MakeIdentifierExpression(
    ParseResultIterator* child_results) {
  auto namespace_qualification =
      child_results->NextAs<std::vector<std::string>>();
  auto name = child_results->NextAs<Identifier*>();
  auto generic_arguments =
      child_results->NextAs<std::vector<TypeExpression*>>();
  Expression* result = MakeNode<IdentifierExpression>(
      std::move(namespace_qualification), name, std::move(generic_arguments));
  return ParseResult{result};
}

base::Optional<ParseResult> MakeFieldAccessExpression(
    ParseResultIterator* child_results) {
  auto object = child_results->NextAs<Expression*>();
  auto field = child_results->NextAs<Identifier*>();
  Expression* result = MakeNode<FieldAccessExpression>(object, field);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeReferenceFieldAccessExpression(
    ParseResultIterator* child_results) {
  auto object = child_results->NextAs<Expression*>();
  auto field = child_results->NextAs<Identifier*>();
  // `a->b` is equivalent to `(*a).b`.
  Expression* deref = MakeNode<DereferenceExpression>(object);
  Expression* result = MakeNode<FieldAccessExpression>(deref, field);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeElementAccessExpression(
    ParseResultIterator* child_results) {
  auto object = child_results->NextAs<Expression*>();
  auto field = child_results->NextAs<Expression*>();
  Expression* result = MakeNode<ElementAccessExpression>(object, field);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeDereferenceExpression(
    ParseResultIterator* child_results) {
  auto reference = child_results->NextAs<Expression*>();
  Expression* result = MakeNode<DereferenceExpression>(reference);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeStructExpression(
    ParseResultIterator* child_results) {
  auto type = child_results->NextAs<TypeExpression*>();
  auto initializers = child_results->NextAs<std::vector<NameAndExpression>>();
  Expression* result =
      MakeNode<StructExpression>(type, std::move(initializers));
  return ParseResult{result};
}

base::Optional<ParseResult> MakeAssignmentExpression(
    ParseResultIterator* child_results) {
  auto location = child_results->NextAs<Expression*>();
  auto op = child_results->NextAs<base::Optional<std::string>>();
  auto value = child_results->NextAs<Expression*>();
  Expression* result =
      MakeNode<AssignmentExpression>(location, std::move(op), value);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeNumberLiteralExpression(
    ParseResultIterator* child_results) {
  auto number = child_results->NextAs<std::string>();
  // TODO(turbofan): Support 64bit literals.
  // Meanwhile, we type it as constexpr float64 when out of int32 range.
  double value = 0;
  try {
#if defined(V8_OS_SOLARIS)
    // stod() on Solaris does not currently support hex strings. Use strtol()
    // specifically for hex literals until stod() support is available.
    if (number.find("0x") == std::string::npos &&
        number.find("0X") == std::string::npos) {
      value = std::stod(number);
    } else {
      value = static_cast<double>(strtol(number.c_str(), nullptr, 0));
    }
#else
    value = std::stod(number);
#endif  // !defined(V8_OS_SOLARIS)
  } catch (const std::out_of_range&) {
    Error("double literal out-of-range").Throw();
  }
  Expression* result = MakeNode<NumberLiteralExpression>(value);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeStringLiteralExpression(
    ParseResultIterator* child_results) {
  auto literal = child_results->NextAs<std::string>();
  Expression* result = MakeNode<StringLiteralExpression>(std::move(literal));
  return ParseResult{result};
}

base::Optional<ParseResult> MakeIncrementDecrementExpressionPostfix(
    ParseResultIterator* child_results) {
  auto location = child_results->NextAs<Expression*>();
  auto op = child_results->NextAs<IncrementDecrementOperator>();
  Expression* result =
      MakeNode<IncrementDecrementExpression>(location, op, true);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeIncrementDecrementExpressionPrefix(
    ParseResultIterator* child_results) {
  auto op = child_results->NextAs<IncrementDecrementOperator>();
  auto location = child_results->NextAs<Expression*>();
  Expression* result =
      MakeNode<IncrementDecrementExpression>(location, op, false);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeLogicalOrExpression(
    ParseResultIterator* child_results) {
  auto left = child_results->NextAs<Expression*>();
  auto right = child_results->NextAs<Expression*>();
  Expression* result = MakeNode<LogicalOrExpression>(left, right);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeLogicalAndExpression(
    ParseResultIterator* child_results) {
  auto left = child_results->NextAs<Expression*>();
  auto right = child_results->NextAs<Expression*>();
  Expression* result = MakeNode<LogicalAndExpression>(left, right);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeConditionalExpression(
    ParseResultIterator* child_results) {
  auto condition = child_results->NextAs<Expression*>();
  auto if_true = child_results->NextAs<Expression*>();
  auto if_false = child_results->NextAs<Expression*>();
  Expression* result =
      MakeNode<ConditionalExpression>(condition, if_true, if_false);
  return ParseResult{result};
}

base::Optional<ParseResult> MakeLabelAndTypes(
    ParseResultIterator* child_results) {
  auto name = child_results->NextAs<Identifier*>();
  if (!IsUpperCamelCase(name->value)) {
    NamingConventionError("Label", name, "UpperCamelCase");
  }
  auto types = child_results->NextAs<std::vector<TypeExpression*>>();
  return ParseResult{LabelAndTypes{name, std::move(types)}};
}

base::Optional<ParseResult> MakeNameAndType(
    ParseResultIterator* child_results) {
  auto name = child_results->NextAs<Identifier*>();
  auto type = child_results->NextAs<TypeExpression*>();
  return ParseResult{NameAndTypeExpression{name, type}};
}

base::Optional<ParseResult> MakeEnumEntry(ParseResultIterator* child_results) {
  auto name = child_results->NextAs<Identifier*>();
  auto type = child_results->NextAs<base::Optional<TypeExpression*>>();
  return ParseResult{EnumEntry{name, type}};
}

base::Optional<ParseResult> MakeNameAndExpression(
    ParseResultIterator* child_results) {
  auto name = child_results->NextAs<Identifier*>();
  auto expression = child_results->NextAs<Expression*>();
  return ParseResult{NameAndExpression{name, expression}};
}

base::Optional<ParseResult> MakeNameAndExpressionFromExpression(
    ParseResultIterator* child_results) {
  auto expression = child_results->NextAs<Expression*>();
  if (auto* id = IdentifierExpression::DynamicCast(expression)) {
    if (!id->generic_arguments.empty() ||
        !id->namespace_qualification.empty()) {
      ReportError("expected a plain identifier without qualification");
    }
    return ParseResult{NameAndExpression{id->name, id}};
  }
  ReportError("Constructor parameters need to be named.");
}

base::Optional<ParseResult> MakeAnnotation(ParseResultIterator* child_results) {
  return ParseResult{
      Annotation{child_results->NextAs<Identifier*>(),
                 child_results->NextAs<base::Optional<AnnotationParameter>>()}};
}

base::Optional<ParseResult> MakeClassField(ParseResultIterator* child_results) {
  AnnotationSet annotations(
      child_results,
      {ANNOTATION_CPP_RELAXED_STORE, ANNOTATION_CPP_RELAXED_LOAD,
       ANNOTATION_CPP_RELEASE_STORE, ANNOTATION_CPP_ACQUIRE_LOAD},
      {ANNOTATION_IF, ANNOTATION_IFNOT});
  FieldSynchronization write_synchronization = FieldSynchronization::kNone;
  if (annotations.Contains(ANNOTATION_CPP_RELEASE_STORE)) {
    write_synchronization = FieldSynchronization::kAcquireRelease;
  } else if (annotations.Contains(ANNOTATION_CPP_RELAXED_STORE)) {
    write_synchronization = FieldSynchronization::kRelaxed;
  }
  FieldSynchronization read_synchronization = FieldSynchronization::kNone;
  if (annotations.Contains(ANNOTATION_CPP_ACQUIRE_LOAD)) {
    read_synchronization = FieldSynchronization::kAcquireRelease;
  } else if (annotations.Contains(ANNOTATION_CPP_RELAXED_LOAD)) {
    read_synchronization = FieldSynchronization::kRelaxed;
  }
  std::vector<ConditionalAnnotation> conditions;
  base::Optional<std::string> if_condition =
      annotations.GetStringParam(ANNOTATION_IF);
  base::Optional<std::string> ifnot_condition =
      annotations.GetStringParam(ANNOTATION_IFNOT);
  if (if_condition.has_value()) {
    conditions.push_back({*if_condition, ConditionalAnnotationType::kPositive});
  }
  if (ifnot_condition.has_value()) {
    conditions.push_back(
        {*ifnot_condition, ConditionalAnnotationType::kNegative});
  }
  auto weak = child_results->NextAs<bool>();
  auto const_qualified = child_results->NextAs<bool>();
  auto name = child_results->NextAs<Identifier*>();
  auto optional = child_results->NextAs<bool>();
  auto index = child_results->NextAs<base::Optional<Expression*>>();
  if (optional && !index) {
    Error(
        "Fields using optional specifier must also provide an expression "
        "indicating the condition for whether the field is present");
  }
  base::Optional<ClassFieldIndexInfo> index_info;
  if (index) {
    if (optional) {
      // Internally, an optional field is just an indexed field where the count
      // is zero or one.
      index = MakeNode<ConditionalExpression>(
          *index, MakeNode<NumberLiteralExpression>(1),
          MakeNode<NumberLiteralExpression>(0));
    }
    index_info = ClassFieldIndexInfo{*index, optional};
  }
  auto type = child_results->NextAs<TypeExpression*>();
  return ParseResult{ClassFieldExpression{{name, type},
                                          index_info,
                                          std::move(conditions),
                                          weak,
                                          const_qualified,
                                          read_synchronization,
                                          write_synchronization}};
}

base::Optional<ParseResult> MakeStructField(
    ParseResultIterator* child_results) {
  auto const_qualified = child_results->NextAs<bool>();
  auto name = child_results->NextAs<Identifier*>();
  auto type = child_results->NextAs<TypeExpression*>();
  return ParseResult{StructFieldExpression{{name, type}, const_qualified}};
}

base::Optional<ParseResult> MakeBitFieldDeclaration(
    ParseResultIterator* child_results) {
  auto name = child_results->NextAs<Identifier*>();
  auto type = child_results->NextAs<TypeExpression*>();
  auto num_bits = child_results->NextAs<int32_t>();
  return ParseResult{BitFieldDeclaration{{name, type}, num_bits}};
}

base::Optional<ParseResult> ExtractAssignmentOperator(
    ParseResultIterator* child_results) {
  auto op = child_results->NextAs<Identifier*>();
  base::Optional<std::string> result =
      std::string(op->value.begin(), op->value.end() - 1);
  return ParseResult(std::move(result));
}

struct TorqueGrammar : Grammar {
  static bool MatchWhitespace(InputPosition* pos) {
    while (true) {
      if (MatchChar(std::isspace, pos)) continue;
      if (MatchString("//", pos)) {
        while (MatchChar([](char c) { return c != '\n'; }, pos)) {
        }
        continue;
      }
      if (MatchString("/*", pos)) {
        while (!MatchString("*/", pos)) ++*pos;
        continue;
      }
      return true;
    }
  }

  static bool MatchIdentifier(InputPosition* pos) {
    InputPosition current = *pos;
    MatchString("_", &current);
    if (!MatchChar(std::isalpha, &current)) return false;
    while (MatchChar(std::isalnum, &current) || MatchString("_", &current)) {
    }
    *pos = current;
    return true;
  }

  static bool MatchAnnotation(InputPosition* pos) {
    InputPosition current = *pos;
    if (!MatchString("@", &current)) return false;
    if (!MatchIdentifier(&current)) return false;
    *pos = current;
    return true;
  }

  static bool MatchIntrinsicName(InputPosition* pos) {
    InputPosition current = *pos;
    if (!MatchString("%", &current)) return false;
    if (!MatchIdentifier(&current)) return false;
    *pos = current;
    return true;
  }

  static bool MatchStringLiteral(InputPosition* pos) {
    InputPosition current = *pos;
    if (MatchString("\"", &current)) {
      while (
          (MatchString("\\", &current) && MatchAnyChar(&current)) ||
          MatchChar([](char c) { return c != '"' && c != '\n'; }, &current)) {
      }
      if (MatchString("\"", &current)) {
        *pos = current;
        return true;
      }
    }
    current = *pos;
    if (MatchString("'", &current)) {
      while (
          (MatchString("\\", &current) && MatchAnyChar(&current)) ||
          MatchChar([](char c) { return c != '\'' && c != '\n'; }, &current)) {
      }
      if (MatchString("'", &current)) {
        *pos = current;
        return true;
      }
    }
    return false;
  }

  static bool MatchHexLiteral(InputPosition* pos) {
    InputPosition current = *pos;
    MatchString("-", &current);
    if (MatchString("0x", &current) && MatchChar(std::isxdigit, &current)) {
      while (MatchChar(std::isxdigit, &current)) {
      }
      *pos = current;
      return true;
    }
    return false;
  }

  static bool MatchDecimalLiteral(InputPosition* pos) {
    InputPosition current = *pos;
    bool found_digit = false;
    MatchString("-", &current);
    while (MatchChar(std::isdigit, &current)) found_digit = true;
    MatchString(".", &current);
    while (MatchChar(std::isdigit, &current)) found_digit = true;
    if (!found_digit) return false;
    *pos = current;
    if ((MatchString("e", &current) || MatchString("E", &current)) &&
        (MatchString("+", &current) || MatchString("-", &current) || true) &&
        MatchChar(std::isdigit, &current)) {
      while (MatchChar(std::isdigit, &current)) {
      }
      *pos = current;
      return true;
    }
    return true;
  }

  TorqueGrammar() : Grammar(&file) { SetWhitespace(MatchWhitespace); }

  // Result: Expression*
  Symbol* expression = &assignmentExpression;

  // Result: std::string
  Symbol identifier = {Rule({Pattern(MatchIdentifier)}, YieldMatchedInput),
                       Rule({Token("runtime")}, YieldMatchedInput)};

  // Result: Identifier*
  Symbol name = {Rule({&identifier}, MakeIdentifier)};

  // Result: Identifier*
  Symbol annotationName = {
      Rule({Pattern(MatchAnnotation)}, MakeIdentifierFromMatchedInput)};

  // Result: std::string
  Symbol intrinsicName = {
      Rule({Pattern(MatchIntrinsicName)}, MakeIdentifierFromMatchedInput)};

  // Result: std::string
  Symbol stringLiteral = {
      Rule({Pattern(MatchStringLiteral)}, YieldMatchedInput)};

  // Result: std::string
  Symbol externalString = {Rule({&stringLiteral}, StringLiteralUnquoteAction)};

  // Result: std::string
  Symbol decimalLiteral = {
      Rule({Pattern(MatchDecimalLiteral)}, YieldMatchedInput),
      Rule({Pattern(MatchHexLiteral)}, YieldMatchedInput)};

  // Result: int32_t
  Symbol int32Literal = {Rule({&decimalLiteral}, MakeInt32)};

  // Result: AnnotationParameter
  Symbol annotationParameter = {
      Rule({&identifier}, MakeStringAnnotationParameter),
      Rule({&int32Literal}, MakeIntAnnotationParameter),
      Rule({&externalString}, MakeStringAnnotationParameter)};

  // Result: AnnotationParameter
  Symbol annotationParameters = {
      Rule({Token("("), &annotationParameter, Token(")")})};

  // Result: Annotation
  Symbol annotation = {Rule(
      {&annotationName, Optional<AnnotationParameter>(&annotationParameters)},
      MakeAnnotation)};

  // Result: std::vector<Annotation>
  Symbol* annotations = List<Annotation>(&annotation);

  // Result: std::vector<std::string>
  Symbol namespaceQualification = {
      Rule({CheckIf(Token("::")),
            List<std::string>(Sequence({&identifier, Token("::")}))},
           MakeNamespaceQualification)};

  // Result: TypeList
  Symbol* typeList = List<TypeExpression*>(&type, Token(","));

  // Result: TypeExpression*
  Symbol simpleType = {
      Rule({Token("("), &type, Token(")")}),
      Rule({&namespaceQualification, CheckIf(Token("constexpr")), &identifier,
            TryOrDefault<std::vector<TypeExpression*>>(
                &genericSpecializationTypeList)},
           MakeBasicTypeExpression),
      Rule({Token("builtin"), Token("("), typeList, Token(")"), Token("=>"),
            &simpleType},
           MakeFunctionTypeExpression),
      Rule({CheckIf(Token("const")), Token("&"), &simpleType},
           MakeReferenceTypeExpression)};

  // Result: TypeExpression*
  Symbol type = {Rule({&simpleType}), Rule({&type, Token("|"), &simpleType},
                                           MakeUnionTypeExpression)};

  // Result: GenericParameter
  Symbol genericParameter = {
      Rule({&name, Token(":"), Token("type"),
            Optional<TypeExpression*>(Sequence({Token("extends"), &type}))},
           MakeGenericParameter)};

  // Result: GenericParameters
  Symbol genericParameters = {
      Rule({Token("<"), List<GenericParameter>(&genericParameter, Token(",")),
            Token(">")})};

  // Result: TypeList
  Symbol genericSpecializationTypeList = {
      Rule({Token("<"), typeList, Token(">")})};

  // Result: base::Optional<GenericParameters>
  Symbol* optionalGenericParameters = Optional<TypeList>(&genericParameters);

  Symbol implicitParameterList{
      Rule({Token("("), OneOf({"implicit", "js-implicit"}),
            List<NameAndTypeExpression>(&nameAndType, Token(",")), Token(")")},
           MakeImplicitParameterList)};

  Symbol* optionalImplicitParameterList{
      Optional<ImplicitParameters>(&implicitParameterList)};

  // Result: ParameterList
  Symbol typeListMaybeVarArgs = {
      Rule({optionalImplicitParameterList, Token("("),
            List<TypeExpression*>(Sequence({&type, Token(",")})), Token("..."),
            Token(")")},
           MakeParameterList<true, false>),
      Rule({optionalImplicitParameterList, Token("("), typeList, Token(")")},
           MakeParameterList<false, false>)};

  // Result: LabelAndTypes
  Symbol labelParameter = {Rule(
      {&name,
       TryOrDefault<TypeList>(Sequence({Token("("), typeList, Token(")")}))},
      MakeLabelAndTypes)};

  // Result: TypeExpression*
  Symbol returnType = {Rule({Token(":"), &type}),
                       Rule({}, DeprecatedMakeVoidType)};

  // Result: LabelAndTypesVector
  Symbol* optionalLabelList{TryOrDefault<LabelAndTypesVector>(
      Sequence({Token("labels"),
                NonemptyList<LabelAndTypes>(&labelParameter, Token(","))}))};

  // Result: std::vector<Statement*>
  Symbol* optionalOtherwise{TryOrDefault<std::vector<Statement*>>(
      Sequence({Token("otherwise"),
                NonemptyList<Statement*>(&atomarStatement, Token(","))}))};

  // Result: NameAndTypeExpression
  Symbol nameAndType = {Rule({&name, Token(":"), &type}, MakeNameAndType)};

  // Result: base::Optional<Expression*>
  Symbol* optionalArraySpecifier =
      Optional<Expression*>(Sequence({Token("["), expression, Token("]")}));

  // Result: ClassFieldExpression
  Symbol classField = {
      Rule({annotations, CheckIf(Token("weak")), CheckIf(Token("const")), &name,
            CheckIf(Token("?")), optionalArraySpecifier, Token(":"), &type,
            Token(";")},
           MakeClassField)};

  // Result: StructFieldExpression
  Symbol structField = {
      Rule({CheckIf(Token("const")), &name, Token(":"), &type, Token(";")},
           MakeStructField)};

  // Result: BitFieldDeclaration
  Symbol bitFieldDeclaration = {Rule({&name, Token(":"), &type, Token(":"),
                                      &int32Literal, Token("bit"), Token(";")},
                                     MakeBitFieldDeclaration)};

  // Result: ParameterList
  Symbol parameterListNoVararg = {
      Rule({optionalImplicitParameterList, Token("("),
            List<NameAndTypeExpression>(&nameAndType, Token(",")), Token(")")},
           MakeParameterList<false, true>)};

  // Result: ParameterList
  Symbol parameterListAllowVararg = {
      Rule({&parameterListNoVararg}),
      Rule({optionalImplicitParameterList, Token("("),
            List<NameAndTypeExpression>(Sequence({&nameAndType, Token(",")})),
            Token("..."), &identifier, Token(")")},
           MakeParameterList<true, true>)};

  // Result: Identifier*
  Symbol* OneOf(const std::vector<std::string>& alternatives) {
    Symbol* result = NewSymbol();
    for (const std::string& s : alternatives) {
      result->AddRule(Rule({Token(s)}, MakeIdentifierFromMatchedInput));
    }
    return result;
  }

  // Result: Expression*
  Symbol* BinaryOperator(Symbol* nextLevel, Symbol* op) {
    Symbol* result = NewSymbol();
    *result = {Rule({nextLevel}),
               Rule({result, op, nextLevel}, MakeBinaryOperator)};
    return result;
  }

  // Result: IncrementDecrementOperator
  Symbol incrementDecrementOperator = {
      Rule({Token("++")},
           YieldIntegralConstant<IncrementDecrementOperator,
                                 IncrementDecrementOperator::kIncrement>),
      Rule({Token("--")},
           YieldIntegralConstant<IncrementDecrementOperator,
                                 IncrementDecrementOperator::kDecrement>)};

  // Result: Expression*
  Symbol identifierExpression = {
      Rule({&namespaceQualification, &name,
            TryOrDefault<TypeList>(&genericSpecializationTypeList)},
           MakeIdentifierExpression),
  };

  // Result: std::vector<Expression*>
  Symbol argumentList = {Rule(
      {Token("("), List<Expression*>(expression, Token(",")), Token(")")})};

  // Result: Expression*
  Symbol callExpression = {Rule(
      {&identifierExpression, &argumentList, optionalOtherwise}, MakeCall)};

  // Result: Expression*
  Symbol callMethodExpression = {Rule(
      {&primaryExpression, Token("."), &name, &argumentList, optionalOtherwise},
      MakeMethodCall)};

  // Result: NameAndExpression
  Symbol namedExpression = {
      Rule({&name, Token(":"), expression}, MakeNameAndExpression),
      Rule({expression}, MakeNameAndExpressionFromExpression)};

  // Result: std::vector<NameAndExpression>
  Symbol initializerList = {
      Rule({Token("{"), List<NameAndExpression>(&namedExpression, Token(",")),
            Token("}")})};

  // Result: Expression*
  Symbol intrinsicCallExpression = {Rule(
      {&intrinsicName, TryOrDefault<TypeList>(&genericSpecializationTypeList),
       &argumentList},
      MakeIntrinsicCallExpression)};

  // Result: Expression*
  Symbol newExpression = {
      Rule({Token("new"),
            CheckIf(Sequence({Token("("), Token("Pretenured"), Token(")")})),
            &simpleType, &initializerList},
           MakeNewExpression)};

  // Result: Expression*
  Symbol primaryExpression = {
      Rule({&callExpression}),
      Rule({&callMethodExpression}),
      Rule({&intrinsicCallExpression}),
      Rule({&identifierExpression}),
      Rule({&primaryExpression, Token("."), &name}, MakeFieldAccessExpression),
      Rule({&primaryExpression, Token("->"), &name},
           MakeReferenceFieldAccessExpression),
      Rule({&primaryExpression, Token("["), expression, Token("]")},
           MakeElementAccessExpression),
      Rule({&decimalLiteral}, MakeNumberLiteralExpression),
      Rule({&stringLiteral}, MakeStringLiteralExpression),
      Rule({&simpleType, &initializerList}, MakeStructExpression),
      Rule({&newExpression}),
      Rule({Token("("), expression, Token(")")})};

  // Result: Expression*
  Symbol unaryExpression = {
      Rule({&primaryExpression}),
      Rule({OneOf({"+", "-", "!", "~", "&"}), &unaryExpression},
           MakeUnaryOperator),
      Rule({Token("*"), &unaryExpression}, MakeDereferenceExpression),
      Rule({Token("..."), &unaryExpression}, MakeSpreadExpression),
      Rule({&incrementDecrementOperator, &unaryExpression},
           MakeIncrementDecrementExpressionPrefix),
      Rule({&unaryExpression, &incrementDecrementOperator},
           MakeIncrementDecrementExpressionPostfix)};

  // Result: Expression*
  Symbol* multiplicativeExpression =
      BinaryOperator(&unaryExpression, OneOf({"*", "/", "%"}));

  // Result: Expression*
  Symbol* additiveExpression =
      BinaryOperator(multiplicativeExpression, OneOf({"+", "-"}));

  // Result: Identifier*
  Symbol shiftOperator = {
      Rule({Token("<<")}, MakeIdentifierFromMatchedInput),
      Rule({Token(">"), Token(">")}, MakeRightShiftIdentifier),
      Rule({Token(">"), Token(">"), Token(">")}, MakeRightShiftIdentifier)};

  // Result: Expression*
  Symbol* shiftExpression = BinaryOperator(additiveExpression, &shiftOperator);

  // Do not allow expressions like a < b > c because this is never
  // useful and ambiguous with template parameters.
  // Result: Expression*
  Symbol relationalExpression = {
      Rule({shiftExpression}),
      Rule({shiftExpression, OneOf({"<", ">", "<=", ">="}), shiftExpression},
           MakeBinaryOperator)};

  // Result: Expression*
  Symbol* equalityExpression =
      BinaryOperator(&relationalExpression, OneOf({"==", "!="}));

  // Result: Expression*
  Symbol* bitwiseExpression =
      BinaryOperator(equalityExpression, OneOf({"&", "|"}));

  // Result: Expression*
  Symbol logicalAndExpression = {
      Rule({bitwiseExpression}),
      Rule({&logicalAndExpression, Token("&&"), bitwiseExpression},
           MakeLogicalAndExpression)};

  // Result: Expression*
  Symbol logicalOrExpression = {
      Rule({&logicalAndExpression}),
      Rule({&logicalOrExpression, Token("||"), &logicalAndExpression},
           MakeLogicalOrExpression)};

  // Result: Expression*
  Symbol conditionalExpression = {
      Rule({&logicalOrExpression}),
      Rule({&logicalOrExpression, Token("?"), expression, Token(":"),
            &conditionalExpression},
           MakeConditionalExpression)};

  // Result: base::Optional<std::string>
  Symbol assignmentOperator = {
      Rule({Token("=")}, YieldDefaultValue<base::Optional<std::string>>),
      Rule({OneOf({"*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=",
                   "^=", "|="})},
           ExtractAssignmentOperator)};

  // Result: Expression*
  Symbol assignmentExpression = {
      Rule({&conditionalExpression}),
      Rule({&conditionalExpression, &assignmentOperator, &assignmentExpression},
           MakeAssignmentExpression)};

  // Result: Statement*
  Symbol block = {Rule({CheckIf(Token("deferred")), Token("{"),
                        List<Statement*>(&statement), Token("}")},
                       MakeBlockStatement)};

  // Result: TryHandler*
  Symbol tryHandler = {
      Rule({Token("label"), &name,
            TryOrDefault<ParameterList>(&parameterListNoVararg), &block},
           MakeLabelBlock),
      Rule({Token("catch"), Token("("), &identifier, Token(")"), &block},
           MakeCatchBlock)};

  // Result: ExpressionWithSource
  Symbol expressionWithSource = {Rule({expression}, MakeExpressionWithSource)};

  Symbol* optionalTypeSpecifier =
      Optional<TypeExpression*>(Sequence({Token(":"), &type}));

  // Result: EnumEntry
  Symbol enumEntry = {Rule({&name, optionalTypeSpecifier}, MakeEnumEntry)};

  // Result: Statement*
  Symbol varDeclaration = {
      Rule({OneOf({"let", "const"}), &name, optionalTypeSpecifier},
           MakeVarDeclarationStatement)};

  // Result: Statement*
  Symbol varDeclarationWithInitialization = {
      Rule({OneOf({"let", "const"}), &name, optionalTypeSpecifier, Token("="),
            expression},
           MakeVarDeclarationStatement)};

  // Result: Statement*
  Symbol atomarStatement = {
      Rule({expression}, MakeExpressionStatement),
      Rule({Token("return"), Optional<Expression*>(expression)},
           MakeReturnStatement),
      Rule({Token("tail"), &callExpression}, MakeTailCallStatement),
      Rule({Token("break")}, MakeBreakStatement),
      Rule({Token("continue")}, MakeContinueStatement),
      Rule({Token("goto"), &name,
            TryOrDefault<std::vector<Expression*>>(&argumentList)},
           MakeGotoStatement),
      Rule({OneOf({"debug", "unreachable"})}, MakeDebugStatement)};

  // Result: Statement*
  Symbol statement = {
      Rule({&block}),
      Rule({&atomarStatement, Token(";")}),
      Rule({&varDeclaration, Token(";")}),
      Rule({&varDeclarationWithInitialization, Token(";")}),
      Rule({Token("if"), CheckIf(Token("constexpr")), Token("("), expression,
            Token(")"), &statement,
            Optional<Statement*>(Sequence({Token("else"), &statement}))},
           MakeIfStatement),
      Rule(
          {
              Token("typeswitch"),
              Token("("),
              expression,
              Token(")"),
              Token("{"),
              NonemptyList<TypeswitchCase>(&typeswitchCase),
              Token("}"),
          },
          MakeTypeswitchStatement),
      Rule({Token("try"), &block, List<TryHandler*>(&tryHandler)},
           MakeTryLabelExpression),
      Rule({OneOf({"dcheck", "check", "static_assert"}), Token("("),
            &expressionWithSource, Token(")"), Token(";")},
           MakeAssertStatement),
      Rule({Token("while"), Token("("), expression, Token(")"), &statement},
           MakeWhileStatement),
      Rule({Token("for"), Token("("),
            Optional<Statement*>(&varDeclarationWithInitialization), Token(";"),
            Optional<Expression*>(expression), Token(";"),
            Optional<Expression*>(expression), Token(")"), &statement},
           MakeForLoopStatement)};

  // Result: TypeswitchCase
  Symbol typeswitchCase = {
      Rule({Token("case"), Token("("),
            Optional<Identifier*>(Sequence({&name, Token(":")})), &type,
            Token(")"), Token(":"), &block},
           MakeTypeswitchCase)};

  // Result: base::Optional<Statement*>
  Symbol optionalBody = {
      Rule({&block}, CastParseResult<Statement*, base::Optional<Statement*>>),
      Rule({Token(";")}, YieldDefaultValue<base::Optional<Statement*>>)};

  // Result: Declaration*
  Symbol method = {Rule(
      {CheckIf(Token("transitioning")),
       Optional<std::string>(Sequence({Token("operator"), &externalString})),
       Token("macro"), &name, &parameterListNoVararg, &returnType,
       optionalLabelList, &block},
      MakeMethodDeclaration)};

  // Result: base::Optional<ClassBody*>
  Symbol optionalClassBody = {
      Rule({Token("{"), List<Declaration*>(&method),
            List<ClassFieldExpression>(&classField), Token("}")},
           MakeClassBody),
      Rule({Token(";")}, YieldDefaultValue<base::Optional<ClassBody*>>)};

  // Result: std::vector<Declaration*>
  Symbol declaration = {
      Rule({Token("const"), &name, Token(":"), &type, Token("="), expression,
            Token(";")},
           AsSingletonVector<Declaration*, MakeConstDeclaration>()),
      Rule({Token("const"), &name, Token(":"), &type, Token("generates"),
            &externalString, Token(";")},
           AsSingletonVector<Declaration*, MakeExternConstDeclaration>()),
      Rule({annotations, CheckIf(Token("extern")), CheckIf(Token("transient")),
            OneOf({"class", "shape"}), &name, Token("extends"), &type,
            Optional<std::string>(
                Sequence({Token("generates"), &externalString})),
            &optionalClassBody},
           MakeClassDeclaration),
      Rule({annotations, Token("struct"), &name,
            TryOrDefault<GenericParameters>(&genericParameters), Token("{"),
            List<Declaration*>(&method),
            List<StructFieldExpression>(&structField), Token("}")},
           AsSingletonVector<Declaration*, MakeStructDeclaration>()),
      Rule({Token("bitfield"), Token("struct"), &name, Token("extends"), &type,
            Token("{"), List<BitFieldDeclaration>(&bitFieldDeclaration),
            Token("}")},
           AsSingletonVector<Declaration*, MakeBitFieldStructDeclaration>()),
      Rule({annotations, CheckIf(Token("transient")), Token("type"), &name,
            TryOrDefault<GenericParameters>(&genericParameters),
            Optional<TypeExpression*>(Sequence({Token("extends"), &type})),
            Optional<std::string>(
                Sequence({Token("generates"), &externalString})),
            Optional<std::string>(
                Sequence({Token("constexpr"), &externalString})),
            Token(";")},
           MakeAbstractTypeDeclaration),
      Rule({Token("type"), &name, Token("="), &type, Token(";")},
           AsSingletonVector<Declaration*, MakeTypeAliasDeclaration>()),
      Rule({Token("intrinsic"), &intrinsicName,
            TryOrDefault<GenericParameters>(&genericParameters),
            &parameterListNoVararg, &returnType, &optionalBody},
           AsSingletonVector<Declaration*, MakeIntrinsicDeclaration>()),
      Rule({Token("extern"), CheckIf(Token("transitioning")),
            Optional<std::string>(
                Sequence({Token("operator"), &externalString})),
            Token("macro"),
            Optional<std::string>(Sequence({&identifier, Token("::")})), &name,
            TryOrDefault<GenericParameters>(&genericParameters),
            &typeListMaybeVarArgs, &returnType, optionalLabelList, Token(";")},
           AsSingletonVector<Declaration*, MakeExternalMacro>()),
      Rule({Token("extern"), CheckIf(Token("transitioning")),
            CheckIf(Token("javascript")), Token("builtin"), &name,
            TryOrDefault<GenericParameters>(&genericParameters),
            &typeListMaybeVarArgs, &returnType, Token(";")},
           AsSingletonVector<Declaration*, MakeExternalBuiltin>()),
      Rule({Token("extern"), CheckIf(Token("transitioning")), Token("runtime"),
            &name, &typeListMaybeVarArgs, &returnType, Token(";")},
           AsSingletonVector<Declaration*, MakeExternalRuntime>()),
      Rule({annotations, CheckIf(Token("transitioning")),
            Optional<std::string>(
                Sequence({Token("operator"), &externalString})),
            Token("macro"), &name,
            TryOrDefault<GenericParameters>(&genericParameters),
            &parameterListNoVararg, &returnType, optionalLabelList,
            &optionalBody},
           AsSingletonVector<Declaration*, MakeTorqueMacroDeclaration>()),
      Rule({CheckIf(Token("transitioning")), CheckIf(Token("javascript")),
            Token("builtin"), &name,
            TryOrDefault<GenericParameters>(&genericParameters),
            &parameterListAllowVararg, &returnType, &optionalBody},
           AsSingletonVector<Declaration*, MakeTorqueBuiltinDeclaration>()),
      Rule({CheckIf(Token("transitioning")), &name,
            &genericSpecializationTypeList, &parameterListAllowVararg,
            &returnType, optionalLabelList, &block},
           AsSingletonVector<Declaration*, MakeSpecializationDeclaration>()),
      Rule({Token("#include"), &externalString},
           AsSingletonVector<Declaration*, MakeCppIncludeDeclaration>()),
      Rule({CheckIf(Token("extern")), Token("enum"), &name,
            Optional<TypeExpression*>(Sequence({Token("extends"), &type})),
            Optional<std::string>(
                Sequence({Token("constexpr"), &externalString})),
            Token("{"), NonemptyList<EnumEntry>(&enumEntry, Token(",")),
            CheckIf(Sequence({Token(","), Token("...")})), Token("}")},
           MakeEnumDeclaration),
      Rule({Token("namespace"), &identifier, Token("{"), &declarationList,
            Token("}")},
           AsSingletonVector<Declaration*, MakeNamespaceDeclaration>())};

  // Result: std::vector<Declaration*>
  Symbol declarationList = {
      Rule({List<std::vector<Declaration*>>(&declaration)}, ConcatList)};

  Symbol file = {Rule({&file, Token("import"), &externalString},
                      ProcessTorqueImportDeclaration),
                 Rule({&file, &declaration}, AddGlobalDeclarations), Rule({})};
};

}  // namespace

void ParseTorque(const std::string& input) {
  BuildFlags::Scope build_flags_scope;
  TorqueGrammar().Parse(input);
}

}  // namespace torque
}  // namespace internal
}  // namespace v8
