Optional JSParserImpl::parseDeclareExportFlow()

in lib/Parser/JSParserImpl-flow.cpp [705:881]


Optional<ESTree::Node *> JSParserImpl::parseDeclareExportFlow(
    SMLoc start,
    AllowDeclareExportType allowDeclareExportType) {
  assert(check(TokenKind::rw_export));
  advance(JSLexer::GrammarContext::Type);
  SMLoc declareStart = tok_->getStartLoc();

  if (checkAndEat(TokenKind::rw_default, JSLexer::GrammarContext::Type)) {
    declareStart = tok_->getStartLoc();
    if (check(TokenKind::rw_function)) {
      auto optFunc = parseDeclareFunctionFlow(declareStart);
      if (!optFunc)
        return None;
      return setLocation(
          start,
          *optFunc,
          new (context_) ESTree::DeclareExportDeclarationNode(
              *optFunc, {}, nullptr, true));
    }
    if (check(TokenKind::rw_class)) {
      auto optClass = parseDeclareClassFlow(declareStart);
      if (!optClass)
        return None;
      return setLocation(
          start,
          *optClass,
          new (context_) ESTree::DeclareExportDeclarationNode(
              *optClass, {}, nullptr, true));
    }
    auto optType = parseTypeAnnotationFlow();
    if (!optType)
      return None;
    if (!eatSemi())
      return None;
    return setLocation(
        start,
        getPrevTokenEndLoc(),
        new (context_)
            ESTree::DeclareExportDeclarationNode(*optType, {}, nullptr, true));
  }

  if (check(TokenKind::rw_function)) {
    auto optFunc = parseDeclareFunctionFlow(declareStart);
    if (!optFunc)
      return None;
    return setLocation(
        start,
        *optFunc,
        new (context_)
            ESTree::DeclareExportDeclarationNode(*optFunc, {}, nullptr, false));
  }

  if (check(TokenKind::rw_class)) {
    auto optClass = parseDeclareClassFlow(declareStart);
    if (!optClass)
      return None;
    return setLocation(
        start,
        *optClass,
        new (context_) ESTree::DeclareExportDeclarationNode(
            *optClass, {}, nullptr, false));
  }

  if (check(TokenKind::rw_var)) {
    SMLoc varStart = advance(JSLexer::GrammarContext::Type).Start;
    auto optIdent = parseBindingIdentifier(Param{});
    if (!optIdent) {
      errorExpected(
          TokenKind::identifier,
          "in var declaration",
          "start of declaration",
          start);
      return None;
    }
    if (!eatSemi())
      return None;

    SMLoc end = getPrevTokenEndLoc();
    return setLocation(
        start,
        end,
        new (context_) ESTree::DeclareExportDeclarationNode(
            setLocation(
                varStart,
                end,
                new (context_) ESTree::DeclareVariableNode(*optIdent)),
            {},
            nullptr,
            false));
  }

  if (checkAndEat(opaqueIdent_, JSLexer::GrammarContext::Type)) {
    if (!check(typeIdent_)) {
      error(tok_->getStartLoc(), "'type' required in opaque type declaration");
      return None;
    }
    advance(JSLexer::GrammarContext::Type);
    auto optType =
        parseTypeAliasFlow(declareStart, TypeAliasKind::DeclareOpaque);
    if (!optType)
      return None;
    return setLocation(
        start,
        *optType,
        new (context_)
            ESTree::DeclareExportDeclarationNode(*optType, {}, nullptr, false));
  }

  if (allowDeclareExportType == AllowDeclareExportType::Yes &&
      check(typeIdent_)) {
    advance(JSLexer::GrammarContext::Type);
    auto optType = parseTypeAliasFlow(declareStart, TypeAliasKind::None);
    if (!optType)
      return None;
    return setLocation(
        start,
        *optType,
        new (context_)
            ESTree::DeclareExportDeclarationNode(*optType, {}, nullptr, false));
  }

  if (checkN(TokenKind::rw_interface, interfaceIdent_)) {
    auto optInterface = parseInterfaceDeclarationFlow();
    if (!optInterface)
      return None;
    return setLocation(
        start,
        *optInterface,
        new (context_) ESTree::DeclareExportDeclarationNode(
            *optInterface, {}, nullptr, false));
  }

  if (checkAndEat(TokenKind::star, JSLexer::GrammarContext::Type)) {
    // declare export * from 'foo';
    //                  ^
    if (!check(fromIdent_)) {
      error(
          tok_->getStartLoc(), "expected 'from' clause in export declaration");
      return None;
    }
    auto optSource = parseFromClause();
    if (!optSource)
      return None;
    if (!eatSemi())
      return None;
    return setLocation(
        start,
        getPrevTokenEndLoc(),
        new (context_) ESTree::DeclareExportAllDeclarationNode(*optSource));
  }

  if (!need(
          TokenKind::l_brace, "in export specifier", "start of declare", start))
    return None;

  ESTree::NodeList specifiers{};
  llvh::SmallVector<SMRange, 2> invalids{};
  if (!parseExportClause(specifiers, invalids))
    return None;

  ESTree::Node *source = nullptr;
  if (check(fromIdent_)) {
    auto optSource = parseFromClause();
    if (!optSource)
      return None;
    source = *optSource;
  }

  if (!eatSemi())
    return None;

  return setLocation(
      start,
      getPrevTokenEndLoc(),
      new (context_) ESTree::DeclareExportDeclarationNode(
          nullptr, std::move(specifiers), source, false));
}