Skip to content

Commit c0ceb7a

Browse files
authored
[Parse] Simplify parsing name for function declarations (#13141)
1 parent 4739fab commit c0ceb7a

File tree

4 files changed

+42
-69
lines changed

4 files changed

+42
-69
lines changed

include/swift/Parse/Parser.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -386,9 +386,6 @@ class Parser {
386386
Pos.PrevLoc);
387387
}
388388

389-
/// \brief Return parser position after the first character of token T
390-
ParserPosition getParserPositionAfterFirstCharacter(Token T);
391-
392389
void restoreParserPosition(ParserPosition PP, bool enableDiagnostics = false) {
393390
L->restoreState(PP.LS, enableDiagnostics);
394391

@@ -594,7 +591,8 @@ class Parser {
594591
/// \brief Consume the starting character of the current token, and split the
595592
/// remainder of the token into a new token (or tokens).
596593
SourceLoc
597-
consumeStartingCharacterOfCurrentToken(tok Kind = tok::oper_binary_unspaced);
594+
consumeStartingCharacterOfCurrentToken(tok Kind = tok::oper_binary_unspaced,
595+
size_t Len = 1);
598596

599597
swift::ScopeInfo &getScopeInfo() { return State->getScopeInfo(); }
600598

lib/Parse/ParseDecl.cpp

Lines changed: 26 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4793,33 +4793,22 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
47934793

47944794
SourceLoc FuncLoc = consumeToken(tok::kw_func);
47954795

4796-
// Forgive the lexer
4797-
if (Tok.is(tok::amp_prefix)) {
4798-
Tok.setKind(tok::oper_prefix);
4799-
}
4796+
// Parse function name.
48004797
Identifier SimpleName;
4801-
Token NameTok = Tok;
48024798
SourceLoc NameLoc;
4803-
4804-
if (Tok.isAny(tok::identifier, tok::integer_literal, tok::floating_literal,
4805-
tok::unknown) ||
4806-
Tok.isKeyword()) {
4807-
// This non-operator path is quite accepting of what tokens might be a name,
4808-
// because we're aggressive about recovering/providing good diagnostics for
4809-
// beginners.
4810-
ParserStatus NameStatus =
4811-
parseIdentifierDeclName(*this, SimpleName, NameLoc, "function",
4812-
tok::l_paren, tok::arrow, tok::l_brace,
4813-
TokenProperty::StartsWithLess);
4814-
if (NameStatus.isError())
4815-
return nullptr;
4816-
} else {
4817-
// May be operator.
4818-
if (parseAnyIdentifier(SimpleName, NameLoc,
4819-
diag::expected_identifier_in_decl, "function")) {
4820-
return nullptr;
4821-
}
4822-
assert(SimpleName.isOperator());
4799+
if (Tok.isAnyOperator() || Tok.isAny(tok::exclaim_postfix, tok::amp_prefix)) {
4800+
// If the name is an operator token that ends in '<' and the following token
4801+
// is an identifier, split the '<' off as a separate token. This allows
4802+
// things like 'func ==<T>(x:T, y:T) {}' to parse as '==' with generic type
4803+
// variable '<T>' as expected.
4804+
auto NameStr = Tok.getText();
4805+
if (NameStr.size() > 1 && NameStr.back() == '<' &&
4806+
peekToken().is(tok::identifier)) {
4807+
NameStr = NameStr.slice(0, NameStr.size() - 1);
4808+
}
4809+
SimpleName = Context.getIdentifier(NameStr);
4810+
NameLoc = consumeStartingCharacterOfCurrentToken(tok::oper_binary_spaced,
4811+
NameStr.size());
48234812
// Within a protocol, recover from a missing 'static'.
48244813
if (Flags & PD_InProtocol) {
48254814
switch (StaticSpelling) {
@@ -4841,6 +4830,15 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
48414830
llvm_unreachable("should have been fixed above");
48424831
}
48434832
}
4833+
} else {
4834+
// This non-operator path is quite accepting of what tokens might be a name,
4835+
// because we're aggressive about recovering/providing good diagnostics for
4836+
// beginners.
4837+
auto NameStatus = parseIdentifierDeclName(
4838+
*this, SimpleName, NameLoc, "function", tok::l_paren, tok::arrow,
4839+
tok::l_brace, TokenProperty::StartsWithLess);
4840+
if (NameStatus.isError())
4841+
return nullptr;
48444842
}
48454843

48464844
DebuggerContextChange DCC(*this, SimpleName, DeclKind::Func);
@@ -4850,30 +4848,9 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
48504848
GenericsScope.emplace(this, ScopeKind::Generics);
48514849
GenericParamList *GenericParams;
48524850
bool SignatureHasCodeCompletion = false;
4853-
// If the name is an operator token that ends in '<' and the following token
4854-
// is an identifier, split the '<' off as a separate token. This allows things
4855-
// like 'func ==<T>(x:T, y:T) {}' to parse as '==' with generic type variable
4856-
// '<T>' as expected.
4857-
if (SimpleName.str().size() > 1 && SimpleName.str().back() == '<'
4858-
&& Tok.is(tok::identifier)) {
4859-
SimpleName = Context.getIdentifier(SimpleName.str().
4860-
slice(0, SimpleName.str().size() - 1));
4861-
SourceLoc LAngleLoc = NameLoc.getAdvancedLoc(SimpleName.str().size());
4862-
auto Result = parseGenericParameters(LAngleLoc);
4863-
GenericParams = Result.getPtrOrNull();
4864-
SignatureHasCodeCompletion |= Result.hasCodeCompletion();
4865-
4866-
auto NameTokText = NameTok.getRawText();
4867-
markSplitToken(tok::identifier,
4868-
NameTokText.substr(0, NameTokText.size() - 1));
4869-
markSplitToken(tok::oper_binary_unspaced,
4870-
NameTokText.substr(NameTokText.size() - 1));
4871-
4872-
} else {
4873-
auto Result = maybeParseGenericParams();
4874-
GenericParams = Result.getPtrOrNull();
4875-
SignatureHasCodeCompletion |= Result.hasCodeCompletion();
4876-
}
4851+
auto GenericParamResult = maybeParseGenericParams();
4852+
GenericParams = GenericParamResult.getPtrOrNull();
4853+
SignatureHasCodeCompletion |= GenericParamResult.hasCodeCompletion();
48774854
if (SignatureHasCodeCompletion && !CodeCompletion)
48784855
return makeParserCodeCompletionStatus();
48794856

lib/Parse/Parser.cpp

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -506,28 +506,26 @@ SourceLoc Parser::getEndOfPreviousLoc() {
506506
return Lexer::getLocForEndOfToken(SourceMgr, PreviousLoc);
507507
}
508508

509-
Parser::ParserPosition Parser::getParserPositionAfterFirstCharacter(Token T) {
510-
assert(T.getLength() > 1 && "Token must have more than one character");
511-
auto Loc = T.getLoc();
512-
auto NewState = L->getStateForBeginningOfTokenLoc(Loc.getAdvancedLoc(1));
513-
return ParserPosition(NewState, Loc);
514-
}
515-
516-
SourceLoc Parser::consumeStartingCharacterOfCurrentToken(tok Kind) {
517-
// Consumes one-character token (like '?', '<', '>' or '!') and returns
518-
// its location.
509+
SourceLoc Parser::consumeStartingCharacterOfCurrentToken(tok Kind, size_t Len) {
510+
// Consumes prefix of token and returns its location.
511+
// (like '?', '<', '>' or '!' immediately followed by '<')
512+
assert(Len >= 1);
519513

520514
// Current token can be either one-character token we want to consume...
521-
if (Tok.getLength() == 1) {
515+
if (Tok.getLength() == Len) {
522516
Tok.setKind(Kind);
523517
return consumeToken();
524518
}
525519

526-
markSplitToken(Kind, Tok.getText().substr(0, 1));
520+
auto Loc = Tok.getLoc();
521+
522+
// ... or a multi-character token with the first N characters being the one
523+
// that we want to consume as a separate token.
524+
assert(Tok.getLength() > Len);
525+
markSplitToken(Kind, Tok.getText().substr(0, Len));
527526

528-
// ... or a multi-character token with the first character being the one that
529-
// we want to consume as a separate token.
530-
restoreParserPosition(getParserPositionAfterFirstCharacter(Tok),
527+
auto NewState = L->getStateForBeginningOfTokenLoc(Loc.getAdvancedLoc(Len));
528+
restoreParserPosition(ParserPosition(NewState, Loc),
531529
/*enableDiagnostics=*/true);
532530
return PreviousLoc;
533531
}

unittests/Parse/TokenizerTests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ TEST_F(TokenizerTest, ProperlySplitTokens) {
155155
"integer_literal: 100\n"
156156
"r_brace: }\n"
157157
"kw_func: func\n"
158-
"identifier: ⊕\n"
158+
"oper_binary_spaced: ⊕\n"
159159
"oper_binary_unspaced: <\n"
160160
"identifier: T\n"
161161
"oper_binary_unspaced: >\n"

0 commit comments

Comments
 (0)