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;
}