Skip to content

Commit 9050f97

Browse files
committed
Specialize Guarded Pattern Parsing for Cases and Catches
Catch patterns are allowed to forgo their pattern, while cases must have patterns. Since these productions have two different types, split these two distinct productions apart. Fixes #1040 rdar://101815618
1 parent e14b79c commit 9050f97

File tree

2 files changed

+43
-23
lines changed

2 files changed

+43
-23
lines changed

Sources/SwiftParser/Statements.swift

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ extension Parser {
490490
var keepGoing: RawTokenSyntax? = nil
491491
var loopProgress = LoopProgressCondition()
492492
repeat {
493-
let (pattern, whereClause) = self.parseGuardedPattern(.catch)
493+
let (pattern, whereClause) = self.parseGuardedCatchPattern()
494494
keepGoing = self.consume(if: .comma)
495495
catchItems.append(RawCatchItemSyntax(
496496
pattern: pattern, whereClause: whereClause, trailingComma: keepGoing,
@@ -505,6 +505,38 @@ extension Parser {
505505
body: body,
506506
arena: self.arena)
507507
}
508+
509+
/// Parse a pattern-matching clause for a catch statement,
510+
/// including the guard expression.
511+
///
512+
/// Grammar
513+
/// =======
514+
///
515+
/// catch-pattern → pattern where-clause?
516+
private mutating func parseGuardedCatchPattern() -> (RawPatternSyntax?, RawWhereClauseSyntax?) {
517+
// If this is a 'catch' clause and we have "catch {" or "catch where...",
518+
// then we get an implicit "let error" pattern.
519+
let pattern: RawPatternSyntax?
520+
if self.at(any: [ .leftBrace, .whereKeyword ]) {
521+
pattern = nil
522+
} else {
523+
pattern = self.parseMatchingPattern(context: .matching)
524+
}
525+
526+
// Parse the optional 'where' guard.
527+
let whereClause: RawWhereClauseSyntax?
528+
if let whereKeyword = self.consume(if: .whereKeyword) {
529+
let guardExpr = self.parseExpression(.basic)
530+
whereClause = RawWhereClauseSyntax(
531+
whereKeyword: whereKeyword,
532+
guardResult: guardExpr,
533+
arena: self.arena
534+
)
535+
} else {
536+
whereClause = nil
537+
}
538+
return (pattern, whereClause)
539+
}
508540
}
509541

510542
// MARK: Iteration Statements
@@ -821,7 +853,7 @@ extension Parser {
821853
var keepGoing: RawTokenSyntax? = nil
822854
var loopProgress = LoopProgressCondition()
823855
repeat {
824-
let (pattern, whereClause) = self.parseGuardedPattern(.case)
856+
let (pattern, whereClause) = self.parseGuardedCasePattern()
825857
keepGoing = self.consume(if: .comma)
826858
caseItems.append(RawCaseItemSyntax(
827859
pattern: pattern, whereClause: whereClause, trailingComma: keepGoing,
@@ -859,39 +891,21 @@ extension Parser {
859891
)
860892
}
861893

862-
enum GuardedPatternContext {
863-
case `case`
864-
case `catch`
865-
}
866-
867-
/// Parse a pattern-matching clause for a case or catch statement,
894+
/// Parse a pattern-matching clause for a case statement,
868895
/// including the guard expression.
869896
///
870897
/// Grammar
871898
/// =======
872899
///
873900
/// case-item → pattern where-clause?
874-
/// catch-pattern → pattern where-clause?
875-
mutating func parseGuardedPattern(
876-
_ context: GuardedPatternContext
877-
) -> (RawPatternSyntax, RawWhereClauseSyntax?) {
878-
let flavor: ExprFlavor
879-
switch context {
880-
// 'case' is terminated with a colon and so allows a trailing closure.
881-
case .`case`:
882-
flavor = .trailingClosure
883-
// 'catch' is terminated with a brace and so cannot.
884-
case .`catch`:
885-
flavor = .basic
886-
}
887-
901+
mutating func parseGuardedCasePattern() -> (RawPatternSyntax, RawWhereClauseSyntax?) {
888902
let pattern = self.parseMatchingPattern(context: .matching)
889903

890904
// Parse the optional 'where' guard, with this particular pattern's bound
891905
// vars in scope.
892906
let whereClause: RawWhereClauseSyntax?
893907
if let whereKeyword = self.consume(if: .whereKeyword) {
894-
let guardExpr = self.parseExpression(flavor)
908+
let guardExpr = self.parseExpression(.trailingClosure)
895909
whereClause = RawWhereClauseSyntax(
896910
whereKeyword: whereKeyword,
897911
guardResult: guardExpr,

Tests/SwiftParserTest/StatementTests.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ final class StatementTests: XCTestCase {
105105
}
106106
"""
107107
)
108+
109+
AssertParse(
110+
"""
111+
do {}
112+
catch where (error as NSError) == NSError() {}
113+
""")
108114
}
109115

110116
func testReturn() {

0 commit comments

Comments
 (0)