in lib/Parser/JSParserImpl.cpp [2562:2990]
Optional<ESTree::Node *> JSParserImpl::parsePropertyAssignment(bool eagerly) {
SMLoc startLoc = tok_->getStartLoc();
ESTree::NodePtr key = nullptr;
SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this};
bool computed = false;
bool generator = false;
bool async = false;
bool method = false;
if (check(getIdent_)) {
UniqueString *ident = tok_->getResWordOrIdentifier();
SMRange identRng = tok_->getSourceRange();
advance();
// This could either be a getter, or a property named 'get'.
if (check(TokenKind::colon, TokenKind::l_paren)) {
// This is just a property.
key = setLocation(
identRng,
identRng,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
#if HERMES_PARSE_FLOW || HERMES_PARSE_TS
} else if (context_.getParseTypes() && check(TokenKind::less)) {
// This is a method definition.
method = true;
key = setLocation(
identRng,
identRng,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
#endif
} else if (check(TokenKind::comma, TokenKind::r_brace)) {
// If the next token is "," or "}", this is a shorthand property
// definition.
key = setLocation(
identRng,
identRng,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
auto *value = setLocation(
key,
key,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
return setLocation(
startLoc,
value,
new (context_)
ESTree::PropertyNode(key, value, initIdent_, false, false, true));
} else {
// A getter method.
computed = check(TokenKind::l_square);
auto optKey = parsePropertyName();
if (!optKey)
return None;
if (!eat(
TokenKind::l_paren,
JSLexer::AllowRegExp,
"in getter declaration",
"start of getter declaration",
startLoc))
return None;
if (!eat(
TokenKind::r_paren,
JSLexer::AllowRegExp,
"in empty getter parameter list",
"start of getter declaration",
startLoc))
return None;
ESTree::Node *returnType = nullptr;
#if HERMES_PARSE_FLOW || HERMES_PARSE_TS
if (context_.getParseTypes() && check(TokenKind::colon)) {
SMLoc annotStart = advance(JSLexer::GrammarContext::Type).Start;
auto optRet = parseTypeAnnotation(annotStart);
if (!optRet)
return None;
returnType = *optRet;
}
#endif
llvh::SaveAndRestore<bool> oldParamYield(paramYield_, false);
llvh::SaveAndRestore<bool> oldParamAwait(paramAwait_, false);
if (!need(
TokenKind::l_brace,
"in getter declaration",
"start of getter declaration",
startLoc))
return None;
auto block = parseFunctionBody(
ParamReturn,
eagerly,
oldParamYield.get(),
oldParamAwait.get(),
JSLexer::AllowRegExp,
true);
if (!block)
return None;
auto *funcExpr = new (context_) ESTree::FunctionExpressionNode(
nullptr,
ESTree::NodeList{},
block.getValue(),
nullptr,
returnType,
/* predicate */ nullptr,
false,
false);
funcExpr->isMethodDefinition = true;
setLocation(startLoc, block.getValue(), funcExpr);
auto *node = new (context_) ESTree::PropertyNode(
optKey.getValue(), funcExpr, getIdent_, computed, false, false);
return setLocation(startLoc, block.getValue(), node);
}
} else if (check(setIdent_)) {
UniqueString *ident = tok_->getResWordOrIdentifier();
SMRange identRng = tok_->getSourceRange();
advance();
// This could either be a setter, or a property named 'set'.
if (check(TokenKind::colon, TokenKind::l_paren)) {
// This is just a property.
key = setLocation(
identRng,
identRng,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
#if HERMES_PARSE_FLOW || HERMES_PARSE_TS
} else if (context_.getParseTypes() && check(TokenKind::less)) {
// This is a method definition.
method = true;
key = setLocation(
identRng,
identRng,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
#endif
} else if (check(TokenKind::comma, TokenKind::r_brace)) {
// If the next token is "," or "}", this is a shorthand property
// definition.
key = setLocation(
identRng,
identRng,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
auto *value = setLocation(
key,
key,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
return setLocation(
startLoc,
value,
new (context_)
ESTree::PropertyNode(key, value, initIdent_, false, false, true));
} else {
// A setter method.
computed = check(TokenKind::l_square);
auto optKey = parsePropertyName();
if (!optKey)
return None;
llvh::SaveAndRestore<bool> oldParamYield(paramYield_, false);
llvh::SaveAndRestore<bool> oldParamAwait(paramAwait_, false);
ESTree::NodeList params;
eat(TokenKind::l_paren,
JSLexer::AllowRegExp,
"in setter declaration",
"start of setter declaration",
startLoc);
// PropertySetParameterList -> FormalParameter -> BindingElement
auto optParam = parseBindingElement(Param{});
if (!optParam)
return None;
params.push_back(**optParam);
if (!eat(
TokenKind::r_paren,
JSLexer::AllowRegExp,
"at end of setter parameter list",
"start of setter declaration",
startLoc))
return None;
ESTree::Node *returnType = nullptr;
#if HERMES_PARSE_FLOW || HERMES_PARSE_TS
if (context_.getParseTypes() && check(TokenKind::colon)) {
SMLoc annotStart = advance(JSLexer::GrammarContext::Type).Start;
auto optRet = parseTypeAnnotation(annotStart);
if (!optRet)
return None;
returnType = *optRet;
}
#endif
if (!need(
TokenKind::l_brace,
"in setter declaration",
"start of setter declaration",
startLoc))
return None;
auto block = parseFunctionBody(
ParamReturn,
eagerly,
oldParamYield.get(),
oldParamAwait.get(),
JSLexer::AllowRegExp,
true);
if (!block)
return None;
auto *funcExpr = new (context_) ESTree::FunctionExpressionNode(
nullptr,
std::move(params),
block.getValue(),
nullptr,
returnType,
/* predicate */ nullptr,
false,
false);
funcExpr->isMethodDefinition = true;
setLocation(startLoc, block.getValue(), funcExpr);
auto *node = new (context_) ESTree::PropertyNode(
optKey.getValue(), funcExpr, setIdent_, computed, false, false);
return setLocation(startLoc, block.getValue(), node);
}
} else if (check(asyncIdent_)) {
UniqueString *ident = tok_->getResWordOrIdentifier();
SMRange identRng = tok_->getSourceRange();
advance();
// This could either be an async function, or a property named 'async'.
if (check(TokenKind::colon, TokenKind::l_paren)) {
// This is just a property (or method) called 'async'.
key = setLocation(
identRng,
identRng,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
#if HERMES_PARSE_FLOW || HERMES_PARSE_TS
} else if (context_.getParseTypes() && check(TokenKind::less)) {
// This is a method definition.
method = true;
key = setLocation(
identRng,
identRng,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
#endif
} else if (check(TokenKind::comma, TokenKind::r_brace)) {
// If the next token is "," or "}", this is a shorthand property
// definition.
key = setLocation(
identRng,
identRng,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
auto *value = setLocation(
key,
key,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
return setLocation(
startLoc,
value,
new (context_)
ESTree::PropertyNode(key, value, initIdent_, false, false, true));
} else {
// This is an async function, parse the key and set `async` to true.
async = true;
method = true;
generator = checkAndEat(TokenKind::star);
computed = check(TokenKind::l_square);
auto optKey = parsePropertyName();
if (!optKey)
return None;
key = optKey.getValue();
}
} else if (check(TokenKind::identifier)) {
auto *ident = tok_->getIdentifier();
key = setLocation(
tok_,
tok_,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
advance();
// If the next token is "," or "}", this is a shorthand property definition.
if (check(TokenKind::comma, TokenKind::r_brace)) {
auto *value = setLocation(
key,
key,
new (context_) ESTree::IdentifierNode(ident, nullptr, false));
return setLocation(
startLoc,
value,
new (context_)
ESTree::PropertyNode(key, value, initIdent_, false, false, true));
}
} else {
generator = checkAndEat(TokenKind::star);
computed = check(TokenKind::l_square);
auto optKey = parsePropertyName();
if (!optKey)
return None;
key = optKey.getValue();
}
ESTree::Node *value;
bool shorthand = false;
if (isa<ESTree::IdentifierNode>(key) && check(TokenKind::equal)) {
// Check for CoverInitializedName: IdentifierReference Initializer
auto startLoc = advance().Start;
auto optInit = parseAssignmentExpression();
if (!optInit)
return None;
shorthand = true;
value = setLocation(
startLoc,
getPrevTokenEndLoc(),
new (context_) ESTree::CoverInitializerNode(*optInit));
} else if (check(TokenKind::l_paren, TokenKind::less) || async) {
// Try this branch when we have '(' or '<' to indicate a method
// or when we know this is async, because async must also indicate a method,
// and we must avoid parsing ordinary properties from ':'.
// Parse the MethodDefinition manually here.
// Do not use `parseClassElement` because we had to parsePropertyName
// in this function ourselves and check for SingleNameBindings, which are
// not parsed with `parsePropertyName`.
// MethodDefinition:
// PropertyName "(" UniqueFormalParameters ")" "{" FunctionBody "}"
// ^
llvh::SaveAndRestore<bool> oldParamYield(paramYield_, generator);
llvh::SaveAndRestore<bool> oldParamAwait(paramAwait_, async);
method = true;
ESTree::Node *typeParams = nullptr;
#if HERMES_PARSE_FLOW
if (context_.getParseFlow() && check(TokenKind::less)) {
auto optTypeParams = parseTypeParamsFlow();
if (!optTypeParams)
return None;
typeParams = *optTypeParams;
}
#endif
#if HERMES_PARSE_TS
if (context_.getParseTS() && check(TokenKind::less)) {
auto optTypeParams = parseTSTypeParameters();
if (!optTypeParams)
return None;
typeParams = *optTypeParams;
}
#endif
// (
if (!need(
TokenKind::l_paren,
"in method definition",
"start of method definition",
startLoc))
return None;
ESTree::NodeList args{};
if (!parseFormalParameters(Param{}, args))
return None;
ESTree::Node *returnType = nullptr;
#if HERMES_PARSE_FLOW || HERMES_PARSE_TS
if (context_.getParseTypes() && check(TokenKind::colon)) {
SMLoc annotStart = advance(JSLexer::GrammarContext::Type).Start;
auto optRet = parseTypeAnnotation(annotStart);
if (!optRet)
return None;
returnType = *optRet;
}
#endif
if (!need(
TokenKind::l_brace,
"in method definition",
"start of method definition",
startLoc))
return None;
auto optBody = parseFunctionBody(
ParamReturn,
eagerly,
oldParamYield.get(),
oldParamAwait.get(),
JSLexer::AllowRegExp,
true);
if (!optBody)
return None;
auto *funcExpr = new (context_) ESTree::FunctionExpressionNode(
nullptr,
std::move(args),
optBody.getValue(),
typeParams,
returnType,
/* predicate */ nullptr,
generator,
async);
funcExpr->isMethodDefinition = true;
setLocation(startLoc, optBody.getValue(), funcExpr);
value = funcExpr;
} else {
if (!eat(
TokenKind::colon,
JSLexer::AllowRegExp,
"in property initialization",
"start of property initialization",
startLoc))
return None;
auto optValue = parseAssignmentExpression();
if (!optValue)
return None;
value = *optValue;
}
return setLocation(
startLoc,
getPrevTokenEndLoc(),
new (context_) ESTree::PropertyNode(
key, value, initIdent_, computed, method, shorthand));
}