bool JSParserImpl::parsePropertyTypeAnnotationFlow()

in lib/Parser/JSParserImpl-flow.cpp [1596:1850]


bool JSParserImpl::parsePropertyTypeAnnotationFlow(
    AllowProtoProperty allowProtoProperty,
    AllowStaticProperty allowStaticProperty,
    ESTree::NodeList &properties,
    ESTree::NodeList &indexers,
    ESTree::NodeList &callProperties,
    ESTree::NodeList &internalSlots) {
  SMRange startRange = tok_->getSourceRange();
  SMLoc start = startRange.Start;

  ESTree::Node *variance = nullptr;
  bool isStatic = false;
  bool proto = false;

  if (check(protoIdent_)) {
    proto = true;
    advance(JSLexer::GrammarContext::Type);
  }

  if (!proto && (check(TokenKind::rw_static) || check(staticIdent_))) {
    isStatic = true;
    advance(JSLexer::GrammarContext::Type);
  }

  if (check(TokenKind::plus, TokenKind::minus)) {
    variance = setLocation(
        tok_,
        tok_,
        new (context_) ESTree::VarianceNode(
            check(TokenKind::plus) ? plusIdent_ : minusIdent_));
    advance(JSLexer::GrammarContext::Type);
  }

  if (checkAndEat(TokenKind::l_square, JSLexer::GrammarContext::Type)) {
    if (checkAndEat(TokenKind::l_square, JSLexer::GrammarContext::Type)) {
      if (variance) {
        error(variance->getSourceRange(), "Unexpected variance sigil");
      }
      if (proto) {
        error(startRange, "invalid 'proto' modifier");
      }
      if (isStatic && allowStaticProperty == AllowStaticProperty::No) {
        error(startRange, "invalid 'static' modifier");
      }
      // Internal slot
      if (!check(TokenKind::identifier) && !tok_->isResWord()) {
        errorExpected(
            TokenKind::identifier,
            "in internal slot",
            "start of internal slot",
            start);
        return false;
      }
      ESTree::IdentifierNode *id = setLocation(
          tok_,
          tok_,
          new (context_) ESTree::IdentifierNode(
              tok_->getResWordOrIdentifier(), nullptr, false));
      advance(JSLexer::GrammarContext::Type);

      if (!eat(
              TokenKind::r_square,
              JSLexer::GrammarContext::Type,
              "at end of internal slot",
              "start of internal slot",
              start))
        return false;
      if (!eat(
              TokenKind::r_square,
              JSLexer::GrammarContext::Type,
              "at end of internal slot",
              "start of internal slot",
              start))
        return false;

      bool optional = false;
      bool method = false;
      ESTree::Node *value = nullptr;

      if (check(TokenKind::less, TokenKind::l_paren)) {
        // Type params and method.
        method = true;
        ESTree::Node *typeParams = nullptr;
        if (check(TokenKind::less)) {
          auto optParams = parseTypeParamsFlow();
          if (!optParams)
            return false;
          typeParams = *optParams;
        }
        auto optMethodish = parseMethodishTypeAnnotationFlow(start, typeParams);
        if (!optMethodish)
          return false;
        value = *optMethodish;
      } else {
        // Standard type annotation.
        optional =
            checkAndEat(TokenKind::question, JSLexer::GrammarContext::Type);
        if (!eat(
                TokenKind::colon,
                JSLexer::GrammarContext::Type,
                "in type annotation",
                "start of annotation",
                start))
          return false;
        auto optValue = parseTypeAnnotationFlow();
        if (!optValue)
          return false;
        value = *optValue;
      }

      assert(value && "value must be set by a branch");
      internalSlots.push_back(*setLocation(
          start,
          getPrevTokenEndLoc(),
          new (context_) ESTree::ObjectTypeInternalSlotNode(
              id, value, optional, isStatic, method)));
    } else {
      // Indexer
      auto optIndexer = parseTypeIndexerPropertyFlow(start, variance, isStatic);
      if (!optIndexer)
        return false;
      if (proto) {
        error(startRange, "invalid 'proto' modifier");
      }
      if (isStatic && allowStaticProperty == AllowStaticProperty::No) {
        error(startRange, "invalid 'static' modifier");
      }
      indexers.push_back(**optIndexer);
    }
    return true;
  }

  ESTree::Node *key = nullptr;

  if (check(TokenKind::less, TokenKind::l_paren)) {
    if ((isStatic && allowStaticProperty == AllowStaticProperty::No) ||
        (proto && allowProtoProperty == AllowProtoProperty::No)) {
      key = setLocation(
          startRange,
          startRange,
          new (context_) ESTree::IdentifierNode(
              isStatic ? staticIdent_ : protoIdent_, nullptr, false));
      isStatic = false;
      proto = false;
      if (variance) {
        error(variance->getSourceRange(), "Unexpected variance sigil");
      }
      auto optProp = parseMethodTypePropertyFlow(start, isStatic, key);
      if (!optProp)
        return false;
      properties.push_back(**optProp);
      return true;
    }
    if (variance != nullptr) {
      error(
          variance->getSourceRange(),
          "call property must not specify variance");
    }
    if (proto) {
      error(startRange, "invalid 'proto' modifier");
    }
    auto optCall = parseTypeCallPropertyFlow(start, isStatic);
    if (!optCall)
      return false;
    callProperties.push_back(**optCall);
    return true;
  }

  if ((isStatic || proto) && check(TokenKind::colon, TokenKind::question)) {
    if (variance) {
      error(variance->getSourceRange(), "Unexpected variance sigil");
    }
    key = setLocation(
        startRange,
        startRange,
        new (context_) ESTree::IdentifierNode(
            isStatic ? staticIdent_ : protoIdent_, nullptr, false));
    isStatic = false;
    proto = false;
    auto optProp = parseTypePropertyFlow(start, variance, isStatic, proto, key);
    if (!optProp)
      return false;
    properties.push_back(**optProp);
    return true;
  }

  auto optKey = parsePropertyName();
  if (!optKey)
    return false;
  key = *optKey;

  if (check(TokenKind::less, TokenKind::l_paren)) {
    if (variance) {
      error(variance->getSourceRange(), "Unexpected variance sigil");
    }
    if (proto) {
      error(startRange, "invalid 'proto' modifier");
    }
    if (isStatic && allowStaticProperty == AllowStaticProperty::No) {
      error(startRange, "invalid 'static' modifier");
    }
    auto optProp = parseMethodTypePropertyFlow(start, isStatic, key);
    if (!optProp)
      return false;
    properties.push_back(**optProp);
    return true;
  }

  if (check(TokenKind::colon, TokenKind::question)) {
    if (proto && allowProtoProperty == AllowProtoProperty::No) {
      error(startRange, "invalid 'proto' modifier");
    }
    if (isStatic && allowStaticProperty == AllowStaticProperty::No) {
      error(startRange, "invalid 'static' modifier");
    }
    auto optProp = parseTypePropertyFlow(start, variance, isStatic, proto, key);
    if (!optProp)
      return false;
    properties.push_back(**optProp);
    return true;
  }

  if (auto *ident = dyn_cast<ESTree::IdentifierNode>(key)) {
    if (ident->_name == getIdent_ || ident->_name == setIdent_) {
      if (variance != nullptr) {
        error(
            variance->getSourceRange(),
            "accessor property must not specify variance");
      }
      if (proto) {
        error(startRange, "invalid 'proto' modifier");
      }
      if (isStatic && allowStaticProperty == AllowStaticProperty::No) {
        error(startRange, "invalid 'static' modifier");
      }
      auto optKey = parsePropertyName();
      if (!optKey)
        return false;
      key = *optKey;
      auto optGetSet = parseGetOrSetTypePropertyFlow(
          start, isStatic, ident->_name == getIdent_, key);
      if (!optGetSet)
        return false;
      properties.push_back(**optGetSet);
      return true;
    }
  }

  errorExpected(
      {TokenKind::colon, TokenKind::question},
      "in property type annotation",
      "start of properties",
      start);
  return false;
}