Optional JSParserImpl::parsePrimaryExpression()

in lib/Parser/JSParserImpl.cpp [2233:2447]


Optional<ESTree::Node *> JSParserImpl::parsePrimaryExpression() {
  CHECK_RECURSION;

  switch (tok_->getKind()) {
    case TokenKind::rw_this: {
      auto *res =
          setLocation(tok_, tok_, new (context_) ESTree::ThisExpressionNode());
      advance(JSLexer::AllowDiv);
      return res;
    }

    case TokenKind::identifier: {
      if (check(yieldIdent_)) {
        // yield is only allowed as an IdentifierReference when ParamYield is
        // false.
        if (paramYield_) {
          error(
              tok_->getSourceRange(),
              "Unexpected usage of 'yield' as an identifier reference");
        }
      }
      if (check(asyncIdent_) && checkAsyncFunction()) {
        auto func = parseFunctionExpression();
        if (!func)
          return None;
        return func.getValue();
      }
      auto *res = setLocation(
          tok_,
          tok_,
          new (context_)
              ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));
      advance(JSLexer::AllowDiv);
      return res;
    }

    case TokenKind::rw_null: {
      auto *res =
          setLocation(tok_, tok_, new (context_) ESTree::NullLiteralNode());
      advance(JSLexer::AllowDiv);
      return res;
    }

    case TokenKind::rw_true:
    case TokenKind::rw_false: {
      auto *res = setLocation(
          tok_,
          tok_,
          new (context_) ESTree::BooleanLiteralNode(
              tok_->getKind() == TokenKind::rw_true));
      advance(JSLexer::AllowDiv);
      return res;
    }

    case TokenKind::numeric_literal: {
      auto *res = setLocation(
          tok_,
          tok_,
          new (context_) ESTree::NumericLiteralNode(tok_->getNumericLiteral()));
      advance(JSLexer::AllowDiv);
      return res;
    }

    case TokenKind::bigint_literal: {
      auto *res = setLocation(
          tok_,
          tok_,
          new (context_) ESTree::BigIntLiteralNode(tok_->getBigIntLiteral()));
      advance(JSLexer::AllowDiv);
      return res;
    }

    case TokenKind::string_literal: {
      auto *res = setLocation(
          tok_,
          tok_,
          new (context_) ESTree::StringLiteralNode(tok_->getStringLiteral()));
      advance(JSLexer::AllowDiv);
      return res;
    }

    case TokenKind::regexp_literal: {
      auto *res = setLocation(
          tok_,
          tok_,
          new (context_) ESTree::RegExpLiteralNode(
              tok_->getRegExpLiteral()->getBody(),
              tok_->getRegExpLiteral()->getFlags()));
      advance(JSLexer::AllowDiv);
      return res;
    }

    case TokenKind::l_square: {
      auto res = parseArrayLiteral();
      if (!res)
        return None;
      return res.getValue();
    }

    case TokenKind::l_brace: {
      auto res = parseObjectLiteral();
      if (!res)
        return None;
      return res.getValue();
    }

    case TokenKind::l_paren: {
      SMLoc startLoc = advance().Start;

      // Cover "()".
      if (check(TokenKind::r_paren)) {
        SMLoc endLoc = advance().End;
        return setLocation(
            startLoc, endLoc, new (context_) ESTree::CoverEmptyArgsNode());
      }

#if HERMES_PARSE_FLOW
      SMLoc startLocAfterParen = tok_->getStartLoc();
#endif

      ESTree::Node *expr;
      if (check(TokenKind::dotdotdot)) {
        auto optRest = parseBindingRestElement(ParamIn);
        if (!optRest)
          return None;

        expr = setLocation(
            *optRest,
            *optRest,
            new (context_) ESTree::CoverRestElementNode(*optRest));
      } else {
        auto optExpr = parseExpression(ParamIn, CoverTypedParameters::Yes);
        if (!optExpr)
          return None;
        expr = *optExpr;
      }

#if HERMES_PARSE_FLOW
      if (context_.getParseFlow()) {
        if (auto *cover = dyn_cast<ESTree::CoverTypedIdentifierNode>(expr)) {
          if (cover->_right && !cover->_optional) {
            expr = setLocation(
                expr,
                getPrevTokenEndLoc(),
                new (context_) ESTree::TypeCastExpressionNode(
                    cover->_left, cover->_right));
          }
        } else if (check(TokenKind::colon)) {
          SMLoc annotStart = advance(JSLexer::GrammarContext::Type).Start;
          auto optType = parseTypeAnnotationFlow(annotStart);
          if (!optType)
            return None;
          ESTree::Node *type = *optType;
          expr = setLocation(
              startLocAfterParen,
              getPrevTokenEndLoc(),
              new (context_) ESTree::TypeCastExpressionNode(expr, type));
        }
      }
#endif

      if (!eat(
              TokenKind::r_paren,
              JSLexer::AllowDiv,
              "at end of parenthesized expression",
              "started here",
              startLoc))
        return None;
      // Record the number of parens surrounding an expression.
      expr->incParens();
      return expr;
    }

    case TokenKind::rw_function: {
      auto fExpr = parseFunctionExpression();
      if (!fExpr)
        return None;
      return fExpr.getValue();
    }

    case TokenKind::rw_class: {
      auto optClass = parseClassExpression();
      if (!optClass)
        return None;
      return optClass.getValue();
    }

    case TokenKind::no_substitution_template:
    case TokenKind::template_head: {
      auto optTemplate = parseTemplateLiteral(Param{});
      if (!optTemplate) {
        return None;
      }
      return optTemplate.getValue();
    }

#if HERMES_PARSE_JSX
    case TokenKind::less:
      if (context_.getParseJSX()) {
        auto optJSX = parseJSX();
        if (!optJSX)
          return None;
        return optJSX.getValue();
      }
      error(
          tok_->getStartLoc(),
          "invalid expression (possible JSX: pass -parse-jsx to parse)");
      return None;
#endif

    default:
      error(tok_->getStartLoc(), "invalid expression");
      return None;
  }
}