Skip to content

Commit b0f8e70

Browse files
authored
Merge pull request #1895 from rintaro/parse-each-self-rdar107450487
[Parser] Accept 'self' after 'each'
2 parents c217d98 + f489551 commit b0f8e70

File tree

2 files changed

+51
-26
lines changed

2 files changed

+51
-26
lines changed

Sources/SwiftParser/Expressions.swift

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,46 @@ extension Parser {
525525
arena: self.arena
526526
)
527527
)
528+
529+
case (.repeat, let handle)?:
530+
// 'repeat' is the start of a pack expansion expression.
531+
return RawExprSyntax(parsePackExpansionExpr(repeatHandle: handle, flavor, pattern: pattern))
532+
533+
case (.each, let handle)?:
534+
// `each` is only contextually a keyword, if it's followed by an
535+
// identifier or 'self' on the same line. We do this to ensure that we do
536+
// not break any 'each' functions defined by users. This is following with
537+
// what we have done for the consume keyword.
538+
switch self.peek() {
539+
case TokenSpec(.identifier, allowAtStartOfLine: false),
540+
TokenSpec(.dollarIdentifier, allowAtStartOfLine: false),
541+
TokenSpec(.self, allowAtStartOfLine: false):
542+
break
543+
default:
544+
// Break out of `outer switch` on failure.
545+
break EXPR_PREFIX
546+
}
547+
548+
let each = self.eat(handle)
549+
let packRef = self.parseSequenceExpressionElement(flavor, pattern: pattern)
550+
return RawExprSyntax(
551+
RawPackElementExprSyntax(
552+
eachKeyword: each,
553+
packRefExpr: packRef,
554+
arena: self.arena
555+
)
556+
)
557+
558+
case (.any, _)?:
559+
// `any` is only contextually a keyword if it's followed by an identifier
560+
// on the same line.
561+
guard case TokenSpec(.identifier, allowAtStartOfLine: false) = self.peek() else {
562+
break EXPR_PREFIX
563+
}
564+
// 'any' is parsed as a part of 'type'.
565+
let type = self.parseType()
566+
return RawExprSyntax(RawTypeExprSyntax(type: type, arena: self.arena))
567+
528568
case nil:
529569
break
530570
}
@@ -549,10 +589,6 @@ extension Parser {
549589
// tryLexRegexLiteral(/*forUnappliedOperator*/ false)
550590

551591
switch self.currentToken {
552-
case TokenSpec(.repeat):
553-
// 'repeat' is the start of a pack expansion expression.
554-
return RawExprSyntax(parsePackExpansionExpr(flavor, pattern: pattern))
555-
556592
// Try parse an 'if' or 'switch' as an expression. Note we do this here in
557593
// parseUnaryExpression as we don't allow postfix syntax to hang off such
558594
// expressions to avoid ambiguities such as postfix '.member', which can
@@ -1234,27 +1270,6 @@ extension Parser {
12341270
return RawExprSyntax(RawUnresolvedPatternExprSyntax(pattern: pattern, arena: self.arena))
12351271
}
12361272

1237-
// We might have a contextual keyword followed by an identifier.
1238-
// 'each <identifier>' is a pack element expr, and 'any <identifier>'
1239-
// is an existential type expr.
1240-
if self.peek().rawTokenKind == .identifier, !self.peek().isAtStartOfLine {
1241-
if self.at(.keyword(.any)) {
1242-
let ty = self.parseType()
1243-
return RawExprSyntax(RawTypeExprSyntax(type: ty, arena: self.arena))
1244-
}
1245-
1246-
if let each = self.consume(if: .keyword(.each)) {
1247-
let packRef = self.parseSequenceExpressionElement(flavor, pattern: pattern)
1248-
return RawExprSyntax(
1249-
RawPackElementExprSyntax(
1250-
eachKeyword: each,
1251-
packRefExpr: packRef,
1252-
arena: self.arena
1253-
)
1254-
)
1255-
}
1256-
}
1257-
12581273
return RawExprSyntax(self.parseIdentifierExpression())
12591274
case (.Self, _)?: // Self
12601275
return RawExprSyntax(self.parseIdentifierExpression())
@@ -1493,10 +1508,11 @@ extension Parser {
14931508
/// pack-expansion-expression → 'repeat' pattern-expression
14941509
/// pattern-expression → expression
14951510
mutating func parsePackExpansionExpr(
1511+
repeatHandle: TokenConsumptionHandle,
14961512
_ flavor: ExprFlavor,
14971513
pattern: PatternContext
14981514
) -> RawPackExpansionExprSyntax {
1499-
let repeatKeyword = self.consumeAnyToken()
1515+
let repeatKeyword = self.eat(repeatHandle)
15001516
let patternExpr = self.parseExpression(flavor, pattern: pattern)
15011517

15021518
return RawPackExpansionExprSyntax(

Sources/SwiftParser/TokenSpecSet.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,9 @@ enum ExpressionModifierKeyword: TokenSpecSet {
616616
case `try`
617617
case consume
618618
case copy
619+
case `repeat`
620+
case each
621+
case any
619622

620623
init?(lexeme: Lexer.Lexeme) {
621624
switch PrepareForKeywordMatch(lexeme) {
@@ -625,6 +628,9 @@ enum ExpressionModifierKeyword: TokenSpecSet {
625628
case TokenSpec(.try): self = .try
626629
case TokenSpec(.consume): self = .consume
627630
case TokenSpec(.copy): self = .copy
631+
case TokenSpec(.repeat): self = .repeat
632+
case TokenSpec(.each): self = .each
633+
case TokenSpec(.any): self = .any
628634
default: return nil
629635
}
630636
}
@@ -637,6 +643,9 @@ enum ExpressionModifierKeyword: TokenSpecSet {
637643
case .consume: return .keyword(.consume)
638644
case .copy: return .keyword(.copy)
639645
case .try: return .keyword(.try)
646+
case .repeat: return .keyword(.repeat)
647+
case .each: return .keyword(.each)
648+
case .any: return .keyword(.any)
640649
}
641650
}
642651
}

0 commit comments

Comments
 (0)