in lib/Parser/JSParserImpl-ts.cpp [227:371]
Optional<ESTree::Node *> JSParserImpl::parseTSFunctionOrParenthesizedType(
SMLoc start,
ESTree::Node *typeParams,
IsConstructorType isConstructorType) {
assert(check(TokenKind::l_paren));
// This is either
// ( Type )
// ^
// or
// ( ParamList ) => Type
// ^
// so we use a similar approach to arrow function parameters by keeping track
// and reparsing in certain cases.
advance(JSLexer::GrammarContext::Type);
bool isFunction = typeParams != nullptr;
bool hasRest = false;
ESTree::Node *type = nullptr;
ESTree::NodeList params{};
if (allowAnonFunctionType_ &&
checkAndEat(TokenKind::dotdotdot, JSLexer::GrammarContext::Type)) {
isFunction = true;
hasRest = true;
// Must be parameters, and this must be the last one.
auto optName = parseTSFunctionTypeParam();
if (!optName)
return None;
params.push_back(*setLocation(
start,
getPrevTokenEndLoc(),
new (context_) ESTree::RestElementNode(*optName)));
} else if (check(TokenKind::l_paren)) {
auto optType = parseTypeAnnotationTS();
if (!optType)
return None;
type = *optType;
} else if (check(TokenKind::r_paren)) {
isFunction = true;
// ( )
// ^
// No parameters, but this must be an empty param list.
} else {
// Not sure yet whether this is a param or simply a type.
auto optParam = parseTSFunctionTypeParam();
if (!optParam)
return None;
if (auto *param =
llvh::dyn_cast<ESTree::TSParameterPropertyNode>(*optParam)) {
if (param &&
(param->_accessibility || param->_export || param->_readonly ||
param->_static)) {
// Must be a param.
isFunction = true;
}
params.push_back(*param);
} else if (
auto *ident = llvh::dyn_cast<ESTree::IdentifierNode>(*optParam)) {
params.push_back(*ident);
type = ident->_typeAnnotation
? ident->_typeAnnotation
: reparseIdentifierAsTSTypeAnnotation(ident);
if (ident->_typeAnnotation || ident->_optional) {
// Must be a param.
isFunction = true;
}
} else {
type = *optParam;
params.push_back(**optParam);
}
}
// If isFunction was already forced by something previously then we
// have no choice but to attempt to parse as a function type annotation.
if ((isFunction || allowAnonFunctionType_) &&
checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type)) {
isFunction = true;
while (!check(TokenKind::r_paren)) {
bool isRest = !hasRest &&
checkAndEat(TokenKind::dotdotdot, JSLexer::GrammarContext::Type);
auto optParam = parseTSFunctionTypeParam();
if (!optParam)
return None;
if (isRest) {
params.push_back(*setLocation(
start,
getPrevTokenEndLoc(),
new (context_) ESTree::RestElementNode(*optParam)));
checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type);
break;
} else {
params.push_back(**optParam);
}
if (!checkAndEat(TokenKind::comma, JSLexer::GrammarContext::Type))
break;
}
}
if (!eat(
TokenKind::r_paren,
JSLexer::GrammarContext::Type,
"at end of function type parameters",
"start of parameters",
start))
return None;
if (isFunction) {
if (!eat(
TokenKind::equalgreater,
JSLexer::GrammarContext::Type,
"in function type",
"start of function",
start))
return None;
} else if (allowAnonFunctionType_) {
if (checkAndEat(TokenKind::equalgreater, JSLexer::GrammarContext::Type)) {
isFunction = true;
}
}
if (!isFunction) {
type->incParens();
return type;
}
auto optReturnType = parseTypeAnnotationTS();
if (!optReturnType)
return None;
if (isConstructorType == IsConstructorType::Yes) {
return setLocation(
start,
getPrevTokenEndLoc(),
new (context_) ESTree::TSConstructorTypeNode(
std::move(params), *optReturnType, typeParams));
}
return setLocation(
start,
getPrevTokenEndLoc(),
new (context_) ESTree::TSFunctionTypeNode(
std::move(params), *optReturnType, typeParams));
}