@@ -67,7 +67,19 @@ extension Parser {
67
67
arena: self . arena
68
68
)
69
69
)
70
- case ( . lhs( . identifier) , let handle) ? :
70
+ case ( . rhs( let introducer) , let handle) ? where self . withLookahead { $0. shouldParsePatternBinding ( introducer: introducer) } :
71
+ let bindingSpecifier = self . eat ( handle)
72
+ let value = self . parsePattern ( )
73
+ return RawPatternSyntax (
74
+ RawValueBindingPatternSyntax (
75
+ bindingSpecifier: bindingSpecifier,
76
+ pattern: value,
77
+ arena: self . arena
78
+ )
79
+ )
80
+ case ( . lhs( . identifier) , let handle) ? ,
81
+ // If we shouldn't contextually parse a pattern binding introducer (because the previous pattern match guard failed), then parse it as an identifier.
82
+ ( . rhs( _) , let handle) ? :
71
83
let identifier = self . eat ( handle)
72
84
return RawPatternSyntax (
73
85
RawIdentifierPatternSyntax (
@@ -85,16 +97,6 @@ extension Parser {
85
97
arena: self . arena
86
98
)
87
99
)
88
- case ( . rhs, let handle) ? :
89
- let bindingSpecifier = self . eat ( handle)
90
- let value = self . parsePattern ( )
91
- return RawPatternSyntax (
92
- RawValueBindingPatternSyntax (
93
- bindingSpecifier: bindingSpecifier,
94
- pattern: value,
95
- arena: self . arena
96
- )
97
- )
98
100
case nil :
99
101
break
100
102
}
@@ -218,7 +220,7 @@ extension Parser {
218
220
arena: self . arena
219
221
)
220
222
)
221
- case ( . rhs, let handle) ? :
223
+ case ( . rhs( let introducer ) , let handle) ? where self . withLookahead { $0 . shouldParsePatternBinding ( introducer : introducer ) } :
222
224
let bindingSpecifier = self . eat ( handle)
223
225
let value = self . parseMatchingPattern ( context: . bindingIntroducer)
224
226
return RawPatternSyntax (
@@ -228,7 +230,8 @@ extension Parser {
228
230
arena: self . arena
229
231
)
230
232
)
231
- case nil :
233
+ case ( . rhs( _) , _) ? ,
234
+ nil :
232
235
break
233
236
}
234
237
@@ -253,6 +256,21 @@ extension Parser {
253
256
// MARK: Lookahead
254
257
255
258
extension Parser . Lookahead {
259
+ /// Returns true if we should parse a pattern binding specifier contextually
260
+ /// as one.
261
+ mutating func shouldParsePatternBinding( introducer: ValueBindingPatternSyntax . BindingSpecifierOptions ) -> Bool {
262
+ switch introducer {
263
+ // TODO: the other ownership modifiers (borrowing/consuming/mutating) more
264
+ // than likely need to be made contextual as well before finalizing their
265
+ // grammar.
266
+ case . _borrowing where experimentalFeatures. contains ( . borrowingSwitch) :
267
+ return peek ( isAt: TokenSpec ( . identifier, allowAtStartOfLine: false ) )
268
+ default :
269
+ // Other keywords can be parsed unconditionally.
270
+ return true
271
+ }
272
+ }
273
+
256
274
/// pattern ::= identifier
257
275
/// pattern ::= '_'
258
276
/// pattern ::= pattern-tuple
@@ -288,15 +306,18 @@ extension Parser.Lookahead {
288
306
>
289
307
290
308
switch self . at ( anyIn: PatternStartTokens . self) {
291
- case ( . lhs( . identifier) , let handle) ? ,
292
- ( . lhs( . wildcard) , let handle) ? :
293
- self . eat ( handle)
294
- return true
295
309
case ( . lhs( . leftParen) , _) ? :
296
310
return self . canParsePatternTuple ( )
297
- case ( . rhs, let handle) ? :
311
+ case ( . rhs( let introducer) , let handle) ? where shouldParsePatternBinding ( introducer: introducer) :
312
+ // Parse as a binding introducer, like `let x`.
298
313
self . eat ( handle)
299
314
return self . canParsePattern ( )
315
+ case ( . lhs( . identifier) , let handle) ? ,
316
+ ( . lhs( . wildcard) , let handle) ? ,
317
+ // If a binding introducer is not contextually introducing a binding, then parse like an identifier.
318
+ ( . rhs( _) , let handle) ? :
319
+ self . eat ( handle)
320
+ return true
300
321
case nil :
301
322
return false
302
323
}
0 commit comments