in lib/Parser/JSParserImpl.cpp [6157:6339]
Optional<ESTree::ImportSpecifierNode *> JSParserImpl::parseImportSpecifier(
SMLoc importLoc) {
// ImportSpecifier:
// ImportedBinding
// IdentifierName as ImportedBinding
SMLoc startLoc = tok_->getStartLoc();
UniqueString *kind = valueIdent_;
ESTree::IdentifierNode *imported = nullptr;
ESTree::IdentifierNode *local = nullptr;
TokenKind localKind;
#if HERMES_PARSE_FLOW
if (context_.getParseFlow() && checkAndEat(TokenKind::rw_typeof)) {
kind = typeofIdent_;
}
#endif
// This isn't wrapped in #if HERMES_PARSE_FLOW, as it is entangled
// in the rest of the import specifier parsing code and doesn't actually
// depend on JSParserImpl-flow specific code at all.
if (HERMES_PARSE_FLOW && context_.getParseFlow() && check(typeIdent_) &&
kind == valueIdent_) {
// Consume 'type', but make no assumptions about what it means yet.
SMRange typeRange = advance();
if (check(TokenKind::r_brace, TokenKind::comma)) {
// 'type'
imported = setLocation(
typeRange,
typeRange,
new (context_) ESTree::IdentifierNode(typeIdent_, nullptr, false));
local = imported;
localKind = TokenKind::identifier;
} else if (check(asIdent_)) {
SMRange asRange = advance();
if (check(TokenKind::r_brace, TokenKind::comma)) {
// 'type' 'as'
kind = typeIdent_;
imported = setLocation(
asRange,
asRange,
new (context_) ESTree::IdentifierNode(asIdent_, nullptr, false));
local = imported;
localKind = TokenKind::identifier;
advance();
} else if (checkAndEat(asIdent_)) {
// 'type' 'as' 'as' Identifier
// ^
if (!check(TokenKind::identifier) && !tok_->isResWord()) {
errorExpected(
TokenKind::identifier,
"in import specifier",
"specifiers start",
importLoc);
return None;
}
kind = typeIdent_;
imported = setLocation(
asRange,
asRange,
new (context_) ESTree::IdentifierNode(asIdent_, nullptr, false));
local = setLocation(
tok_,
tok_,
new (context_) ESTree::IdentifierNode(
tok_->getResWordOrIdentifier(), nullptr, false));
localKind = TokenKind::identifier;
advance();
} else {
// 'type' 'as' Identifier
// ^
if (!check(TokenKind::identifier) && !tok_->isResWord()) {
errorExpected(
TokenKind::identifier,
"in import specifier",
"specifiers start",
importLoc);
return None;
}
imported = setLocation(
typeRange,
typeRange,
new (context_) ESTree::IdentifierNode(typeIdent_, nullptr, false));
local = setLocation(
tok_,
tok_,
new (context_) ESTree::IdentifierNode(
tok_->getResWordOrIdentifier(), nullptr, false));
localKind = TokenKind::identifier;
advance();
}
} else {
// 'type' Identifier
// ^
kind = typeIdent_;
if (!check(TokenKind::identifier) && !tok_->isResWord()) {
errorExpected(
TokenKind::identifier,
"in import specifier",
"specifiers start",
importLoc);
return None;
}
imported = setLocation(
tok_,
tok_,
new (context_) ESTree::IdentifierNode(
tok_->getResWordOrIdentifier(), nullptr, false));
local = imported;
localKind = tok_->getKind();
advance();
if (checkAndEat(asIdent_)) {
// type Identifier 'as' Identifier
// ^
if (!check(TokenKind::identifier) && !tok_->isResWord()) {
errorExpected(
TokenKind::identifier,
"in import specifier",
"specifiers start",
importLoc);
return None;
}
local = setLocation(
tok_,
tok_,
new (context_) ESTree::IdentifierNode(
tok_->getResWordOrIdentifier(), nullptr, false));
localKind = tok_->getKind();
advance();
}
}
} else {
// Not attempting to parse a type identifier.
if (!check(TokenKind::identifier) && !tok_->isResWord()) {
errorExpected(
TokenKind::identifier,
"in import specifier",
"specifiers start",
importLoc);
return None;
}
imported = setLocation(
tok_,
tok_,
new (context_) ESTree::IdentifierNode(
tok_->getResWordOrIdentifier(), nullptr, false));
local = imported;
localKind = tok_->getKind();
advance();
if (checkAndEat(asIdent_)) {
if (!check(TokenKind::identifier) && !tok_->isResWord()) {
errorExpected(
TokenKind::identifier,
"in import specifier",
"specifiers start",
importLoc);
return None;
}
local = setLocation(
tok_,
tok_,
new (context_) ESTree::IdentifierNode(
tok_->getResWordOrIdentifier(), nullptr, false));
localKind = tok_->getKind();
advance();
}
}
// Only the local name must be parsed as a binding identifier.
// We need to check for 'as' before knowing what the local name is.
// Thus, we need to validate the binding identifier for the local name
// after the fact.
if (!validateBindingIdentifier(
Param{}, local->getSourceRange(), local->_name, localKind)) {
error(local->getSourceRange(), "Invalid local name for import");
}
return setLocation(
startLoc,
getPrevTokenEndLoc(),
new (context_) ESTree::ImportSpecifierNode(imported, local, kind));
}