Skip to content

Commit 52cfbaf

Browse files
committed
[Parser] Accept 'self' after 'each'
Also move 'repeat', 'each', and 'any' expression parsing to 'parseSequenceExpressionElement'. rdar://107450487
1 parent ed52edd commit 52cfbaf

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

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

1227-
// We might have a contextual keyword followed by an identifier.
1228-
// 'each <identifier>' is a pack element expr, and 'any <identifier>'
1229-
// is an existential type expr.
1230-
if self.peek().rawTokenKind == .identifier, !self.peek().isAtStartOfLine {
1231-
if self.at(.keyword(.any)) {
1232-
let ty = self.parseType()
1233-
return RawExprSyntax(RawTypeExprSyntax(type: ty, arena: self.arena))
1234-
}
1235-
1236-
if let each = self.consume(if: .keyword(.each)) {
1237-
let packRef = self.parseSequenceExpressionElement(flavor, pattern: pattern)
1238-
return RawExprSyntax(
1239-
RawPackElementExprSyntax(
1240-
eachKeyword: each,
1241-
packRefExpr: packRef,
1242-
arena: self.arena
1243-
)
1244-
)
1245-
}
1246-
}
1247-
12481263
return RawExprSyntax(self.parseIdentifierExpression())
12491264
case (.Self, _)?: // Self
12501265
return RawExprSyntax(self.parseIdentifierExpression())
@@ -1441,10 +1456,11 @@ extension Parser {
14411456
/// pack-expansion-expression → 'repeat' pattern-expression
14421457
/// pattern-expression → expression
14431458
mutating func parsePackExpansionExpr(
1459+
repeatHandle: TokenConsumptionHandle,
14441460
_ flavor: ExprFlavor,
14451461
pattern: PatternContext
14461462
) -> RawPackExpansionExprSyntax {
1447-
let repeatKeyword = self.consumeAnyToken()
1463+
let repeatKeyword = self.eat(repeatHandle)
14481464
let patternExpr = self.parseExpression(flavor, pattern: pattern)
14491465

14501466
return RawPackExpansionExprSyntax(

Sources/SwiftParser/TokenSpecSet.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,9 @@ enum ExpressionModifierKeyword: TokenSpecSet {
464464
case `try`
465465
case consume
466466
case copy
467+
case `repeat`
468+
case each
469+
case any
467470

468471
init?(lexeme: Lexer.Lexeme) {
469472
switch PrepareForKeywordMatch(lexeme) {
@@ -473,6 +476,9 @@ enum ExpressionModifierKeyword: TokenSpecSet {
473476
case TokenSpec(.try): self = .try
474477
case TokenSpec(.consume): self = .consume
475478
case TokenSpec(.copy): self = .copy
479+
case TokenSpec(.repeat): self = .repeat
480+
case TokenSpec(.each): self = .each
481+
case TokenSpec(.any): self = .any
476482
default: return nil
477483
}
478484
}
@@ -485,6 +491,9 @@ enum ExpressionModifierKeyword: TokenSpecSet {
485491
case .consume: return .keyword(.consume)
486492
case .copy: return .keyword(.copy)
487493
case .try: return .keyword(.try)
494+
case .repeat: return .keyword(.repeat)
495+
case .each: return .keyword(.each)
496+
case .any: return .keyword(.any)
488497
}
489498
}
490499
}

0 commit comments

Comments
 (0)