Skip to content

Commit 87f0d2e

Browse files
committed
Generalize "InVarOrLetPattern" to "PatternContext"
1 parent 720da6e commit 87f0d2e

File tree

3 files changed

+64
-45
lines changed

3 files changed

+64
-45
lines changed

Sources/SwiftParser/Attributes.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ extension Parser {
117117
leftParen: nil, argumentList: nil, rightParen: nil,
118118
arena: self.arena)
119119
}
120-
let arguments = self.parseArgumentListElements(inLetOrVar: false)
120+
let arguments = self.parseArgumentListElements(pattern: .none)
121121
let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)
122122
return RawCustomAttributeSyntax(
123123
unexpectedBeforeAtSign,

Sources/SwiftParser/Expressions.swift

Lines changed: 61 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,23 @@ extension Parser {
3333
case trailingClosure
3434
}
3535

36+
public enum PatternContext {
37+
case none
38+
case matching
39+
case `var`
40+
case `let`
41+
case implicitlyImmutable
42+
43+
var admitsBinding: Bool {
44+
switch self {
45+
case .implicitlyImmutable, .var, .let:
46+
return true
47+
case .none, .matching:
48+
return false
49+
}
50+
}
51+
}
52+
3653
/// Parse an expression.
3754
///
3855
/// Grammar
@@ -41,7 +58,7 @@ extension Parser {
4158
/// expression → try-operator? await-operator? prefix-expression infix-expressions?
4259
/// expression-list → expression | expression ',' expression-list
4360
@_spi(RawSyntax)
44-
public mutating func parseExpression(_ flavor: ExprFlavor = .trailingClosure, inLetOrVar: Bool = false) -> RawExprSyntax {
61+
public mutating func parseExpression(_ flavor: ExprFlavor = .trailingClosure, pattern: PatternContext = .none) -> RawExprSyntax {
4562
// If we are parsing a refutable pattern, check to see if this is the start
4663
// of a let/var/is pattern. If so, parse it as an UnresolvedPatternExpr and
4764
// let pattern type checking determine its final form.
@@ -52,7 +69,7 @@ extension Parser {
5269
let pattern = self.parseMatchingPattern()
5370
return RawExprSyntax(RawUnresolvedPatternExprSyntax(pattern: pattern, arena: self.arena))
5471
}
55-
return RawExprSyntax(self.parseSequenceExpression(flavor, inVarOrLet: inLetOrVar))
72+
return RawExprSyntax(self.parseSequenceExpression(flavor, pattern: pattern))
5673
}
5774
}
5875

@@ -71,7 +88,7 @@ extension Parser {
7188
public mutating func parseSequenceExpression(
7289
_ flavor: ExprFlavor,
7390
forDirective: Bool = false,
74-
inVarOrLet: Bool = false
91+
pattern: PatternContext = .none
7592
) -> RawExprSyntax {
7693
if forDirective && self.currentToken.isAtStartOfLine {
7794
return RawExprSyntax(RawMissingExprSyntax(arena: self.arena))
@@ -87,7 +104,7 @@ extension Parser {
87104

88105
lastElement = self.parseSequenceExpressionElement(flavor,
89106
forDirective: forDirective,
90-
inVarOrLet: inVarOrLet)
107+
pattern: pattern)
91108

92109
var loopCondition = LoopProgressCondition()
93110
while loopCondition.evaluate(currentToken) {
@@ -101,7 +118,7 @@ extension Parser {
101118
// Parse the operator.
102119
guard
103120
let (operatorExpr, rhsExpr) =
104-
self.parseSequenceExpressionOperator(flavor, inVarOrLet: inVarOrLet)
121+
self.parseSequenceExpressionOperator(flavor, pattern: pattern)
105122
else {
106123
// Not an operator. We're done.
107124
break
@@ -120,7 +137,7 @@ extension Parser {
120137
} else {
121138
lastElement = self.parseSequenceExpressionElement(flavor,
122139
forDirective: forDirective,
123-
inVarOrLet: inVarOrLet)
140+
pattern: pattern)
124141
}
125142
}
126143

@@ -160,7 +177,7 @@ extension Parser {
160177
/// arrow-operator -> 'throws' '->'
161178
/// arrow-operator -> 'async' 'throws' '->'
162179
mutating func parseSequenceExpressionOperator(
163-
_ flavor: ExprFlavor, inVarOrLet: Bool
180+
_ flavor: ExprFlavor, pattern: PatternContext
164181
) -> (operator: RawExprSyntax, rhs: RawExprSyntax?)? {
165182
enum ExpectedTokenKind: RawTokenKindSubset {
166183
case spacedBinaryOperator
@@ -220,7 +237,7 @@ extension Parser {
220237
case (.infixQuestionMark, let handle)?:
221238
// Save the '?'.
222239
let question = self.eat(handle)
223-
let firstChoice = self.parseSequenceExpression(flavor, inVarOrLet: inVarOrLet)
240+
let firstChoice = self.parseSequenceExpression(flavor, pattern: pattern)
224241
// Make sure there's a matching ':' after the middle expr.
225242
let (unexpectedBeforeColon, colon) = self.expect(.colon)
226243

@@ -243,16 +260,18 @@ extension Parser {
243260
return (RawExprSyntax(op), rhs)
244261

245262
case (.equal, let handle)?:
246-
if inVarOrLet {
263+
switch pattern {
264+
case .matching, .let, .var:
247265
return nil
248-
} else {
266+
case .none, .implicitlyImmutable:
249267
let eq = self.eat(handle)
250268
let op = RawAssignmentExprSyntax(
251269
assignToken: eq,
252270
arena: self.arena
253271
)
254272
return (RawExprSyntax(op), nil)
255273
}
274+
256275

257276
case (.isKeyword, let handle)?:
258277
let isKeyword = self.eat(handle)
@@ -320,7 +339,7 @@ extension Parser {
320339
public mutating func parseSequenceExpressionElement(
321340
_ flavor: ExprFlavor,
322341
forDirective: Bool = false,
323-
inVarOrLet: Bool = false
342+
pattern: PatternContext = .none
324343
) -> RawExprSyntax {
325344
// Try to parse '@' sign or 'inout' as a attributed typerepr.
326345
if self.at(any: [.atSign, .inoutKeyword]) {
@@ -336,7 +355,7 @@ extension Parser {
336355
case (.awaitContextualKeyword, let handle)?:
337356
let awaitTok = self.eat(handle)
338357
let sub = self.parseSequenceExpressionElement(
339-
flavor, forDirective: forDirective, inVarOrLet: inVarOrLet)
358+
flavor, forDirective: forDirective, pattern: pattern)
340359
return RawExprSyntax(RawAwaitExprSyntax(
341360
awaitKeyword: awaitTok,
342361
expression: sub,
@@ -347,7 +366,7 @@ extension Parser {
347366
let mark = self.consume(ifAny: [.exclamationMark, .postfixQuestionMark])
348367

349368
let expression = self.parseSequenceExpressionElement(
350-
flavor, forDirective: forDirective, inVarOrLet: inVarOrLet)
369+
flavor, forDirective: forDirective, pattern: pattern)
351370
return RawExprSyntax(RawTryExprSyntax(
352371
tryKeyword: tryKeyword,
353372
questionOrExclamationMark: mark,
@@ -357,13 +376,13 @@ extension Parser {
357376
case (._moveContextualKeyword, let handle)?:
358377
let moveTok = self.eat(handle)
359378
let sub = self.parseSequenceExpressionElement(
360-
flavor, forDirective: forDirective, inVarOrLet: inVarOrLet)
379+
flavor, forDirective: forDirective, pattern: pattern)
361380
return RawExprSyntax(RawMoveExprSyntax(
362381
moveKeyword: moveTok,
363382
expression: sub,
364383
arena: self.arena))
365384
case nil:
366-
return self.parseUnaryExpression(flavor, forDirective: forDirective, inVarOrLet: inVarOrLet)
385+
return self.parseUnaryExpression(flavor, forDirective: forDirective, pattern: pattern)
367386
}
368387
}
369388

@@ -380,26 +399,26 @@ extension Parser {
380399
public mutating func parseUnaryExpression(
381400
_ flavor: ExprFlavor,
382401
forDirective: Bool = false,
383-
inVarOrLet: Bool = false
402+
pattern: PatternContext = .none
384403
) -> RawExprSyntax {
385404
// First check to see if we have the start of a regex literal `/.../`.
386405
// tryLexRegexLiteral(/*forUnappliedOperator*/ false)
387406
switch self.at(anyIn: ExpressionPrefixOperator.self) {
388407
case (.prefixAmpersand, let handle)?:
389408
let amp = self.eat(handle)
390-
let expr = self.parseUnaryExpression(flavor, forDirective: forDirective, inVarOrLet: inVarOrLet)
409+
let expr = self.parseUnaryExpression(flavor, forDirective: forDirective, pattern: pattern)
391410
return RawExprSyntax(RawInOutExprSyntax(
392411
ampersand: amp,
393412
expression: RawExprSyntax(expr),
394413
arena: self.arena
395414
))
396415

397416
case (.backslash, _)?:
398-
return RawExprSyntax(self.parseKeyPathExpression(forDirective: forDirective, inVarOrLet: inVarOrLet))
417+
return RawExprSyntax(self.parseKeyPathExpression(forDirective: forDirective, pattern: pattern))
399418

400419
case (.prefixOperator, let handle)?:
401420
let op = self.eat(handle)
402-
let postfix = self.parseUnaryExpression(flavor, forDirective: forDirective, inVarOrLet: inVarOrLet)
421+
let postfix = self.parseUnaryExpression(flavor, forDirective: forDirective, pattern: pattern)
403422
return RawExprSyntax(RawPrefixOperatorExprSyntax(
404423
operatorToken: op,
405424
postfixExpression: postfix,
@@ -409,7 +428,7 @@ extension Parser {
409428
default:
410429
// If the next token is not an operator, just parse this as expr-postfix.
411430
return self.parsePostfixExpression(
412-
flavor, forDirective: forDirective, inVarOrLet: inVarOrLet,
431+
flavor, forDirective: forDirective, pattern: pattern,
413432
periodHasKeyPathBehavior: false)
414433
}
415434
}
@@ -432,16 +451,16 @@ extension Parser {
432451
public mutating func parsePostfixExpression(
433452
_ flavor: ExprFlavor,
434453
forDirective: Bool,
435-
inVarOrLet: Bool,
454+
pattern: PatternContext,
436455
periodHasKeyPathBehavior: Bool
437456
) -> RawExprSyntax {
438-
let head = self.parsePrimaryExpression(inVarOrLet: inVarOrLet)
457+
let head = self.parsePrimaryExpression(pattern: pattern)
439458
guard !head.is(RawMissingExprSyntax.self) else {
440459
return head
441460
}
442461
return self.parsePostfixExpressionSuffix(
443462
head, flavor, forDirective: forDirective,
444-
periodHasKeyPathBehavior: periodHasKeyPathBehavior, inLetOrVar: inVarOrLet)
463+
periodHasKeyPathBehavior: periodHasKeyPathBehavior, pattern: pattern)
445464
}
446465

447466
@_spi(RawSyntax)
@@ -503,7 +522,7 @@ extension Parser {
503522
let result = parser.parsePostfixExpressionSuffix(
504523
head, flavor, forDirective: forDirective,
505524
periodHasKeyPathBehavior: false,
506-
inLetOrVar: false
525+
pattern: .none
507526
)
508527

509528
// TODO: diagnose and skip the remaining token in the current clause.
@@ -541,7 +560,7 @@ extension Parser {
541560
_ flavor: ExprFlavor,
542561
forDirective: Bool,
543562
periodHasKeyPathBehavior: Bool,
544-
inLetOrVar: Bool
563+
pattern: PatternContext
545564
) -> RawExprSyntax {
546565
// Handle suffix expressions.
547566
var leadingExpr = start
@@ -568,7 +587,7 @@ extension Parser {
568587

569588
// If there is an expr-call-suffix, parse it and form a call.
570589
if let lparen = self.consume(if: .leftParen, where: { !$0.isAtStartOfLine }) {
571-
let args = self.parseArgumentListElements(inLetOrVar: inLetOrVar)
590+
let args = self.parseArgumentListElements(pattern: pattern)
572591
let (unexpectedBeforeRParen, rparen) = self.expect(.rightParen)
573592

574593
// If we can parse trailing closures, do so.
@@ -600,7 +619,7 @@ extension Parser {
600619
if self.at(.rightSquareBracket) {
601620
args = []
602621
} else {
603-
args = self.parseArgumentListElements(inLetOrVar: inLetOrVar)
622+
args = self.parseArgumentListElements(pattern: pattern)
604623
}
605624
let (unexpectedBeforeRSquare, rsquare) = self.expect(.rightSquareBracket)
606625

@@ -731,7 +750,7 @@ extension Parser {
731750
/// key-path-postfixes → key-path-postfix key-path-postfixes?
732751
/// key-path-postfix → '?' | '!' | 'self' | '[' function-call-argument-list ']'
733752
@_spi(RawSyntax)
734-
public mutating func parseKeyPathExpression(forDirective: Bool, inVarOrLet: Bool) -> RawKeyPathExprSyntax {
753+
public mutating func parseKeyPathExpression(forDirective: Bool, pattern: PatternContext) -> RawKeyPathExprSyntax {
735754
// Consume '\'.
736755
let (unexpectedBeforeBackslash, backslash) = self.expect(.backslash)
737756

@@ -743,7 +762,7 @@ extension Parser {
743762
let root: RawExprSyntax?
744763
if !self.currentToken.starts(with: ".") {
745764
root = self.parsePostfixExpression(
746-
.basic, forDirective: forDirective, inVarOrLet: inVarOrLet,
765+
.basic, forDirective: forDirective, pattern: pattern,
747766
periodHasKeyPathBehavior: true)
748767
} else {
749768
root = nil
@@ -761,7 +780,7 @@ extension Parser {
761780
expression = self.parsePostfixExpressionSuffix(
762781
base, .basic, forDirective: forDirective,
763782
periodHasKeyPathBehavior: false,
764-
inLetOrVar: inVarOrLet
783+
pattern: pattern
765784
)
766785
} else if self.at(any: [.period, .prefixPeriod]) {
767786
// Inside a keypath's path, the period always behaves normally: the key path
@@ -770,7 +789,7 @@ extension Parser {
770789
expression = self.parsePostfixExpressionSuffix(
771790
base, .basic, forDirective: forDirective,
772791
periodHasKeyPathBehavior: false,
773-
inLetOrVar: inVarOrLet
792+
pattern: pattern
774793
)
775794
} else {
776795
expression = RawExprSyntax(RawMissingExprSyntax(arena: self.arena))
@@ -805,7 +824,7 @@ extension Parser {
805824
/// primary-expression → selector-expression
806825
/// primary-expression → key-path-string-expression
807826
@_spi(RawSyntax)
808-
public mutating func parsePrimaryExpression(inVarOrLet: Bool) -> RawExprSyntax {
827+
public mutating func parsePrimaryExpression(pattern: PatternContext) -> RawExprSyntax {
809828
switch self.at(anyIn: PrimaryExpressionStart.self) {
810829
case (.integerLiteral, let handle)?:
811830
let digits = self.eat(handle)
@@ -912,7 +931,7 @@ extension Parser {
912931
// If we have "case let x." or "case let x(", we parse x as a normal
913932
// name, not a binding, because it is the start of an enum pattern or
914933
// call pattern.
915-
if inVarOrLet && !self.lookahead().isNextTokenCallPattern() {
934+
if pattern.admitsBinding && !self.lookahead().isNextTokenCallPattern() {
916935
let identifier = self.eat(handle)
917936
let pattern = RawPatternSyntax(RawIdentifierPatternSyntax(
918937
identifier: identifier, arena: self.arena))
@@ -970,7 +989,7 @@ extension Parser {
970989
// only one element without label. However, libSyntax tree doesn't have this
971990
// differentiation. A tuple expression node in libSyntax can have a single
972991
// element without label.
973-
return RawExprSyntax(self.parseTupleExpression(inLetOrVar: inVarOrLet))
992+
return RawExprSyntax(self.parseTupleExpression(pattern: pattern))
974993

975994
case (.leftSquareBracket, _)?:
976995
return self.parseCollectionLiteral()
@@ -1026,7 +1045,7 @@ extension Parser {
10261045
public mutating func parseObjectLiteralExpression() -> RawObjectLiteralExprSyntax {
10271046
let poundKeyword = self.consumeAnyToken()
10281047
let (unexpectedBeforeLeftParen, leftParen) = self.expect(.leftParen)
1029-
let arguments = self.parseArgumentListElements(inLetOrVar: false)
1048+
let arguments = self.parseArgumentListElements(pattern: .none)
10301049
let (unexpectedBeforeRightParen, rightParen) = self.expect(.rightParen)
10311050
return RawObjectLiteralExprSyntax(
10321051
identifier: poundKeyword,
@@ -1380,7 +1399,7 @@ extension Parser {
13801399
expressionContent.withBuffer { buf in
13811400
var subparser = Parser(buf, arena: self.arena)
13821401
let (lunexpected, lparen) = subparser.expect(.leftParen)
1383-
let args = subparser.parseArgumentListElements(inLetOrVar: false)
1402+
let args = subparser.parseArgumentListElements(pattern: .none)
13841403
// If we stopped parsing the expression before the expression segment is
13851404
// over, eat the remaining tokens into a token list.
13861405
var runexpectedTokens = [RawSyntax]()
@@ -1540,9 +1559,9 @@ extension Parser {
15401559
/// tuple-expression → '(' ')' | '(' tuple-element ',' tuple-element-list ')'
15411560
/// tuple-element-list → tuple-element | tuple-element ',' tuple-element-list
15421561
@_spi(RawSyntax)
1543-
public mutating func parseTupleExpression(inLetOrVar: Bool) -> RawTupleExprSyntax {
1562+
public mutating func parseTupleExpression(pattern: PatternContext) -> RawTupleExprSyntax {
15441563
let (unexpectedBeforeLParen, lparen) = self.expect(.leftParen)
1545-
let elements = self.parseArgumentListElements(inLetOrVar: inLetOrVar)
1564+
let elements = self.parseArgumentListElements(pattern: pattern)
15461565
let (unexpectedBeforeRParen, rparen) = self.expect(.rightParen)
15471566
return RawTupleExprSyntax(
15481567
unexpectedBeforeLParen,
@@ -2009,7 +2028,7 @@ extension Parser {
20092028
///
20102029
/// tuple-element → expression | identifier ':' expression
20112030
@_spi(RawSyntax)
2012-
public mutating func parseArgumentListElements(inLetOrVar: Bool) -> [RawTupleExprElementSyntax] {
2031+
public mutating func parseArgumentListElements(pattern: PatternContext) -> [RawTupleExprElementSyntax] {
20132032
guard !self.at(.rightParen) else {
20142033
return []
20152034
}
@@ -2031,7 +2050,7 @@ extension Parser {
20312050
expr = RawExprSyntax(RawIdentifierExprSyntax(
20322051
identifier: ident, declNameArguments: args, arena: self.arena))
20332052
} else {
2034-
expr = self.parseExpression(inLetOrVar: inLetOrVar)
2053+
expr = self.parseExpression(pattern: pattern)
20352054
}
20362055
keepGoing = self.consume(if: .comma)
20372056
result.append(RawTupleExprElementSyntax(
@@ -2056,9 +2075,9 @@ extension Parser {
20562075
/// tuple-expression → '(' ')' | '(' tuple-element ',' tuple-element-list ')'
20572076
/// tuple-element-list → tuple-element | tuple-element ',' tuple-element-list
20582077
@_spi(RawSyntax)
2059-
public mutating func parseArgumentList(_ flavor: ExprFlavor, inLetOrVar: Bool) -> RawTupleExprSyntax {
2078+
public mutating func parseArgumentList(_ flavor: ExprFlavor, pattern: PatternContext) -> RawTupleExprSyntax {
20602079
let (unexpectedBeforeLParen, lparen) = self.expect(.leftParen)
2061-
let args = self.parseArgumentListElements(inLetOrVar: inLetOrVar)
2080+
let args = self.parseArgumentListElements(pattern: pattern)
20622081
let (unexpectedBeforeRightParen, rparen) = self.expect(.rightParen)
20632082

20642083
// FIXME: Introduce new SyntaxKind for ArgumentList (rdar://81786229)

0 commit comments

Comments
 (0)