Optional JSParserImpl::parseExportDeclaration()

in lib/Parser/JSParserImpl.cpp [6341:6525]


Optional<ESTree::Node *> JSParserImpl::parseExportDeclaration() {
  assert(
      check(TokenKind::rw_export) &&
      "parseExportDeclaration requires 'export'");
  SMLoc startLoc = advance().Start;

#if HERMES_PARSE_FLOW
  if (context_.getParseFlow() && check(typeIdent_)) {
    return parseExportTypeDeclarationFlow(startLoc);
  }
#endif

  if (checkAndEat(TokenKind::star)) {
    // export * FromClause;
    // export * as IdentifierName FromClause;
    ESTree::Node *exportAs = nullptr;
    if (checkAndEat(asIdent_)) {
      // export * as IdentifierName FromClause;
      //             ^
      if (!check(TokenKind::identifier) && !tok_->isResWord()) {
        errorExpected(
            TokenKind::identifier,
            "in export clause",
            "start of export",
            startLoc);
        return None;
      }
      exportAs = setLocation(
          tok_,
          tok_,
          new (context_) ESTree::IdentifierNode(
              tok_->getResWordOrIdentifier(), nullptr, false));
      advance();
    }
    auto optFromClause = parseFromClause();
    if (!optFromClause) {
      return None;
    }
    if (!eatSemi()) {
      return None;
    }
    if (exportAs) {
      ESTree::NodeList specifiers{};
      specifiers.push_back(*setLocation(
          startLoc,
          getPrevTokenEndLoc(),
          new (context_) ESTree::ExportNamespaceSpecifierNode(exportAs)));
      return setLocation(
          startLoc,
          getPrevTokenEndLoc(),
          new (context_) ESTree::ExportNamedDeclarationNode(
              nullptr, std::move(specifiers), *optFromClause, valueIdent_));
    }
    return setLocation(
        startLoc,
        getPrevTokenEndLoc(),
        new (context_)
            ESTree::ExportAllDeclarationNode(*optFromClause, valueIdent_));
  } else if (checkAndEat(TokenKind::rw_default)) {
    // export default
    if (check(TokenKind::rw_function) ||
        (check(asyncIdent_) && checkAsyncFunction())) {
      // export default HoistableDeclaration
      // Currently, the only hoistable declarations are functions.
      auto optFunDecl = parseFunctionDeclaration(ParamDefault);
      if (!optFunDecl) {
        return None;
      }
      return setLocation(
          startLoc,
          *optFunDecl,
          new (context_) ESTree::ExportDefaultDeclarationNode(*optFunDecl));
    } else if (check(TokenKind::rw_class)) {
      auto optClassDecl = parseClassDeclaration(ParamDefault);
      if (!optClassDecl) {
        return None;
      }
      return setLocation(
          startLoc,
          *optClassDecl,
          new (context_) ESTree::ExportDefaultDeclarationNode(*optClassDecl));
#if HERMES_PARSE_FLOW
    } else if (context_.getParseFlow() && check(TokenKind::rw_enum)) {
      auto optEnum = parseEnumDeclarationFlow();
      if (!optEnum) {
        return None;
      }
      return setLocation(
          startLoc,
          *optEnum,
          new (context_) ESTree::ExportDefaultDeclarationNode(*optEnum));
#endif
    } else {
      // export default AssignmentExpression ;
      auto optExpr = parseAssignmentExpression(ParamIn);
      if (!optExpr) {
        return None;
      }
      if (!eatSemi()) {
        return None;
      }
      return setLocation(
          startLoc,
          getPrevTokenEndLoc(),
          new (context_) ESTree::ExportDefaultDeclarationNode(*optExpr));
    }
  } else if (check(TokenKind::l_brace)) {
    // export ExportClause FromClause ;
    // export ExportClause ;
    ESTree::NodeList specifiers{};
    llvh::SmallVector<SMRange, 2> invalids{};

    auto optExportClause = parseExportClause(specifiers, invalids);
    if (!optExportClause) {
      return None;
    }

    ESTree::Node *source = nullptr;
    if (check(fromIdent_)) {
      // export ExportClause FromClause ;
      auto optFromClause = parseFromClause();
      if (!optFromClause) {
        return None;
      }
      source = *optFromClause;
    } else {
      // export ExportClause ;
      // ES9.0 15.2.3.1
      // When there is no FromClause, any ranges added to invalids are actually
      // invalid, and should be reported as errors.
      for (const SMRange &range : invalids) {
        error(range, "Invalid exported name");
      }
    }

    if (!eatSemi()) {
      return None;
    }

    return setLocation(
        startLoc,
        getPrevTokenEndLoc(),
        new (context_) ESTree::ExportNamedDeclarationNode(
            nullptr, std::move(specifiers), source, valueIdent_));
  } else if (check(TokenKind::rw_var)) {
    // export VariableStatement
    auto optVar = parseVariableStatement(Param{});
    if (!optVar) {
      return None;
    }
    return setLocation(
        startLoc,
        *optVar,
        new (context_) ESTree::ExportNamedDeclarationNode(
            *optVar, {}, nullptr, valueIdent_));
  }

  // export Declaration [~Yield]

  if (!checkDeclaration()) {
    error(tok_->getSourceRange(), "expected declaration in export");
    return None;
  }

  auto optDecl = parseDeclaration(Param{});
  if (!optDecl) {
    return None;
  }
  ESTree::Node *decl = *optDecl;

  UniqueString *kind = valueIdent_;
#if HERMES_PARSE_FLOW
  if (isa<ESTree::TypeAliasNode>(decl) || isa<ESTree::OpaqueTypeNode>(decl) ||
      isa<ESTree::DeclareTypeAliasNode>(decl) ||
      isa<ESTree::InterfaceDeclarationNode>(decl)) {
    kind = typeIdent_;
  }
#endif

  return setLocation(
      startLoc,
      decl,
      new (context_)
          ESTree::ExportNamedDeclarationNode(decl, {}, nullptr, kind));
}