Skip to content

Commit b4ac843

Browse files
committed
[Parse] Simplify parsing name for function declarations
1 parent 9e7687f commit b4ac843

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
@@ -4807,33 +4807,22 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
48074807

48084808
SourceLoc FuncLoc = consumeToken(tok::kw_func);
48094809

4810-
// Forgive the lexer
4811-
if (Tok.is(tok::amp_prefix)) {
4812-
Tok.setKind(tok::oper_prefix);
4813-
}
4810+
// Parse function name.
48144811
Identifier SimpleName;
4815-
Token NameTok = Tok;
48164812
SourceLoc NameLoc;
4817-
4818-
if (Tok.isAny(tok::identifier, tok::integer_literal, tok::floating_literal,
4819-
tok::unknown) ||
4820-
Tok.isKeyword()) {
4821-
// This non-operator path is quite accepting of what tokens might be a name,
4822-
// because we're aggressive about recovering/providing good diagnostics for
4823-
// beginners.
4824-
ParserStatus NameStatus =
4825-
parseIdentifierDeclName(*this, SimpleName, NameLoc, "function",
4826-
tok::l_paren, tok::arrow, tok::l_brace,
4827-
TokenProperty::StartsWithLess);
4828-
if (NameStatus.isError())
4829-
return nullptr;
4830-
} else {
4831-
// May be operator.
4832-
if (parseAnyIdentifier(SimpleName, NameLoc,
4833-
diag::expected_identifier_in_decl, "function")) {
4834-
return nullptr;
4835-
}
4836-
assert(SimpleName.isOperator());
4813+
if (Tok.isAnyOperator() || Tok.isAny(tok::exclaim_postfix, tok::amp_prefix)) {
4814+
// If the name is an operator token that ends in '<' and the following token
4815+
// is an identifier, split the '<' off as a separate token. This allows
4816+
// things like 'func ==<T>(x:T, y:T) {}' to parse as '==' with generic type
4817+
// variable '<T>' as expected.
4818+
auto NameStr = Tok.getText();
4819+
if (NameStr.size() > 1 && NameStr.back() == '<' &&
4820+
peekToken().is(tok::identifier)) {
4821+
NameStr = NameStr.slice(0, NameStr.size() - 1);
4822+
}
4823+
SimpleName = Context.getIdentifier(NameStr);
4824+
NameLoc = consumeStartingCharacterOfCurrentToken(tok::oper_binary_spaced,
4825+
NameStr.size());
48374826
// Within a protocol, recover from a missing 'static'.
48384827
if (Flags & PD_InProtocol) {
48394828
switch (StaticSpelling) {
@@ -4855,6 +4844,15 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
48554844
llvm_unreachable("should have been fixed above");
48564845
}
48574846
}
4847+
} else {
4848+
// This non-operator path is quite accepting of what tokens might be a name,
4849+
// because we're aggressive about recovering/providing good diagnostics for
4850+
// beginners.
4851+
auto NameStatus = parseIdentifierDeclName(
4852+
*this, SimpleName, NameLoc, "function", tok::l_paren, tok::arrow,
4853+
tok::l_brace, TokenProperty::StartsWithLess);
4854+
if (NameStatus.isError())
4855+
return nullptr;
48584856
}
48594857

48604858
DebuggerContextChange DCC(*this, SimpleName, DeclKind::Func);
@@ -4864,30 +4862,9 @@ Parser::parseDeclFunc(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
48644862
GenericsScope.emplace(this, ScopeKind::Generics);
48654863
GenericParamList *GenericParams;
48664864
bool SignatureHasCodeCompletion = false;
4867-
// If the name is an operator token that ends in '<' and the following token
4868-
// is an identifier, split the '<' off as a separate token. This allows things
4869-
// like 'func ==<T>(x:T, y:T) {}' to parse as '==' with generic type variable
4870-
// '<T>' as expected.
4871-
if (SimpleName.str().size() > 1 && SimpleName.str().back() == '<'
4872-
&& Tok.is(tok::identifier)) {
4873-
SimpleName = Context.getIdentifier(SimpleName.str().
4874-
slice(0, SimpleName.str().size() - 1));
4875-
SourceLoc LAngleLoc = NameLoc.getAdvancedLoc(SimpleName.str().size());
4876-
auto Result = parseGenericParameters(LAngleLoc);
4877-
GenericParams = Result.getPtrOrNull();
4878-
SignatureHasCodeCompletion |= Result.hasCodeCompletion();
4879-
4880-
auto NameTokText = NameTok.getRawText();
4881-
markSplitToken(tok::identifier,
4882-
NameTokText.substr(0, NameTokText.size() - 1));
4883-
markSplitToken(tok::oper_binary_unspaced,
4884-
NameTokText.substr(NameTokText.size() - 1));
4885-
4886-
} else {
4887-
auto Result = maybeParseGenericParams();
4888-
GenericParams = Result.getPtrOrNull();
4889-
SignatureHasCodeCompletion |= Result.hasCodeCompletion();
4890-
}
4865+
auto GenericParamResult = maybeParseGenericParams();
4866+
GenericParams = GenericParamResult.getPtrOrNull();
4867+
SignatureHasCodeCompletion |= GenericParamResult.hasCodeCompletion();
48914868
if (SignatureHasCodeCompletion && !CodeCompletion)
48924869
return makeParserCodeCompletionStatus();
48934870

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)