@@ -55,7 +55,8 @@ extension TokenConsumer {
55
55
mutating func atStartOfDeclaration(
56
56
isAtTopLevel: Bool = false ,
57
57
allowInitDecl: Bool = true ,
58
- allowRecovery: Bool = false
58
+ allowRecovery: Bool = false ,
59
+ requiresDecl: Bool = false ,
59
60
) -> Bool {
60
61
if self . at ( . poundIf) {
61
62
return true
@@ -132,15 +133,15 @@ extension TokenConsumer {
132
133
case . lhs( . case) :
133
134
// When 'case' appears inside a function, it's probably a switch
134
135
// case, not an enum case declaration.
135
- return false
136
+ return requiresDecl
136
137
case . lhs( . `init`) :
137
138
return allowInitDecl
138
139
case . lhs( . macro) :
139
140
// macro Foo ...
140
141
return subparser. peek ( ) . rawTokenKind == . identifier
141
142
case . lhs( . pound) :
142
143
// Force parsing '#<identifier>' after attributes as a macro expansion decl.
143
- if hasAttribute || hasModifier {
144
+ if hasAttribute || hasModifier || requiresDecl {
144
145
return true
145
146
}
146
147
@@ -181,8 +182,25 @@ extension TokenConsumer {
181
182
allowRecovery: allowRecovery
182
183
)
183
184
}
184
- if allowRecovery && ( hasAttribute || hasModifier ) {
185
+ if requiresDecl {
185
186
// If we found any attributes or modifiers, consider it's a missing decl.
187
+ if hasAttribute || hasModifier {
188
+ return true
189
+ }
190
+ if subparser. atFunctionDeclarationWithoutFuncKeyword ( ) {
191
+ return true
192
+ }
193
+ if subparser. atBindingDeclarationWithoutVarKeyword ( ) {
194
+ return true
195
+ }
196
+ if subparser. currentToken. isEditorPlaceholder {
197
+ return true
198
+ }
199
+ }
200
+ // Special recovery 'try let/var'.
201
+ if subparser. at ( . keyword( . try ) ) ,
202
+ subparser. peek ( isAtAnyIn: VariableDeclSyntax . BindingSpecifierOptions. self) != nil
203
+ {
186
204
return true
187
205
}
188
206
return false
@@ -199,6 +217,10 @@ extension Parser {
199
217
self . attributes = attributes
200
218
self . modifiers = modifiers
201
219
}
220
+
221
+ var isEmpty : Bool {
222
+ attributes. isEmpty && modifiers. isEmpty
223
+ }
202
224
}
203
225
204
226
/// Describes the context around a declaration in order to modify how it is parsed.
@@ -267,8 +289,8 @@ extension Parser {
267
289
semicolon: semicolon,
268
290
arena: parser. arena
269
291
)
270
- } addSemicolonIfNeeded: { lastElement, newItemAtStartOfLine, parser in
271
- if lastElement. semicolon == nil && !newItemAtStartOfLine {
292
+ } addSemicolonIfNeeded: { lastElement, newItemAtStartOfLine, newItem , parser in
293
+ if lastElement. semicolon == nil && !newItemAtStartOfLine && !newItem . decl . is ( RawUnexpectedCodeDeclSyntax . self ) {
272
294
return RawMemberBlockItemSyntax (
273
295
lastElement. unexpectedBeforeDecl,
274
296
decl: lastElement. decl,
@@ -313,11 +335,11 @@ extension Parser {
313
335
// We aren't at a declaration keyword and it looks like we are at a function
314
336
// declaration. Parse a function declaration.
315
337
recoveryResult = ( . lhs( . func) , . missing( . keyword( . func) ) )
338
+ } else if atBindingDeclarationWithoutVarKeyword ( ) {
339
+ recoveryResult = ( . rhs( . var) , . missing( . keyword( . var) ) )
316
340
} else {
317
341
// In all other cases, use standard token recovery to find the declaration
318
342
// to parse.
319
- // If we are inside a memberDecl list, we don't want to eat closing braces (which most likely close the outer context)
320
- // while recovering to the declaration start.
321
343
recoveryResult = self . canRecoverTo (
322
344
anyIn: DeclarationKeyword . self,
323
345
overrideRecoveryPrecedence: context. recoveryPrecedence
@@ -380,13 +402,6 @@ extension Parser {
380
402
}
381
403
382
404
if context. requiresDecl {
383
- let isProbablyVarDecl = self . at ( . identifier, . wildcard) && self . peek ( isAt: . colon, . equal, . comma)
384
- let isProbablyTupleDecl = self . at ( . leftParen) && self . peek ( isAt: . identifier, . wildcard)
385
-
386
- if isProbablyVarDecl || isProbablyTupleDecl {
387
- return RawDeclSyntax ( self . parseBindingDeclaration ( attrs, . missing( . keyword( . var) ) , in: context) )
388
- }
389
-
390
405
if self . currentToken. isEditorPlaceholder {
391
406
let placeholder = self . parseAnyIdentifier ( )
392
407
return RawDeclSyntax (
@@ -398,10 +413,6 @@ extension Parser {
398
413
)
399
414
)
400
415
}
401
-
402
- if atFunctionDeclarationWithoutFuncKeyword ( ) {
403
- return RawDeclSyntax ( self . parseFuncDeclaration ( attrs, . missing( . keyword( . func) ) ) )
404
- }
405
416
}
406
417
return RawDeclSyntax (
407
418
RawMissingDeclSyntax (
@@ -411,6 +422,27 @@ extension Parser {
411
422
)
412
423
)
413
424
}
425
+ }
426
+
427
+ extension TokenConsumer {
428
+ /// Returns `true` if it looks like the parser is positioned at a variable declaration that’s missing the `var` keyword.
429
+ fileprivate mutating func atBindingDeclarationWithoutVarKeyword( ) -> Bool {
430
+ if self . at ( . identifier, . wildcard) ,
431
+ self . peek ( isAt: . colon, . equal, . comma)
432
+ {
433
+ return true
434
+ }
435
+ if self . at ( . leftParen) ,
436
+ self . peek ( isAt: . identifier, . wildcard) ,
437
+ self . withLookahead ( {
438
+ $0. skipSingle ( ) ; return $0. at ( . colon, . equal)
439
+ } )
440
+ {
441
+ return true
442
+ }
443
+
444
+ return false
445
+ }
414
446
415
447
/// Returns `true` if it looks like the parser is positioned at a function declaration that’s missing the `func` keyword.
416
448
fileprivate mutating func atFunctionDeclarationWithoutFuncKeyword( ) -> Bool {
@@ -983,20 +1015,35 @@ extension Parser {
983
1015
let decl : RawDeclSyntax
984
1016
if self . at ( . poundSourceLocation) {
985
1017
decl = RawDeclSyntax ( self . parsePoundSourceLocationDirective ( ) )
986
- } else {
1018
+ } else if self . atStartOfDeclaration ( isAtTopLevel : false , allowInitDecl : true , requiresDecl : true ) {
987
1019
decl = self . parseDeclaration ( in: . memberDeclList)
1020
+ } else {
1021
+ decl = RawDeclSyntax (
1022
+ self . parseUnexpectedCodeDeclaration (
1023
+ isAtTopLevel: false ,
1024
+ allowInitDecl: true ,
1025
+ requiresDecl: true ,
1026
+ skipToDeclOnly: true
1027
+ )
1028
+ )
988
1029
}
989
1030
990
- let semi = self . consume ( if: . semicolon)
1031
+ if decl. isEmpty && !self . at ( . semicolon) {
1032
+ return nil
1033
+ }
1034
+
1035
+ let semi : RawTokenSyntax ?
1036
+ if !decl. isEmpty {
1037
+ semi = self . consume ( if: . semicolon)
1038
+ } else {
1039
+ // orphan ';' case. Put it to "unexpected" nodes.
1040
+ semi = nil
1041
+ }
991
1042
var trailingSemis : [ RawTokenSyntax ] = [ ]
992
1043
while let trailingSemi = self . consume ( if: . semicolon) {
993
1044
trailingSemis. append ( trailingSemi)
994
1045
}
995
1046
996
- if decl. isEmpty && semi == nil && trailingSemis. isEmpty {
997
- return nil
998
- }
999
-
1000
1047
let result = RawMemberBlockItemSyntax (
1001
1048
decl: decl,
1002
1049
semicolon: semi,
@@ -1013,12 +1060,14 @@ extension Parser {
1013
1060
var elements = [ RawMemberBlockItemSyntax] ( )
1014
1061
do {
1015
1062
var loopProgress = LoopProgressCondition ( )
1016
- while !self . at ( . endOfFile, . rightBrace) && self . hasProgressed ( & loopProgress) {
1063
+ while !self . at ( . endOfFile, . rightBrace, . poundEndif ) && self . hasProgressed ( & loopProgress) {
1017
1064
let newItemAtStartOfLine = self . atStartOfLine
1018
1065
guard let newElement = self . parseMemberBlockItem ( ) else {
1019
1066
break
1020
1067
}
1021
- if let lastItem = elements. last, lastItem. semicolon == nil && !newItemAtStartOfLine {
1068
+ if let lastItem = elements. last,
1069
+ lastItem. semicolon == nil && !newItemAtStartOfLine && !newElement. decl. is ( RawUnexpectedCodeDeclSyntax . self)
1070
+ {
1022
1071
elements [ elements. count - 1 ] = RawMemberBlockItemSyntax (
1023
1072
lastItem. unexpectedBeforeDecl,
1024
1073
decl: lastItem. decl,
@@ -1039,7 +1088,15 @@ extension Parser {
1039
1088
/// If the left brace is missing, its indentation will be used to judge whether a following `}` was
1040
1089
/// indented to close this code block or a surrounding context. See `expectRightBrace`.
1041
1090
mutating func parseMemberBlock( introducer: RawTokenSyntax ? = nil ) -> RawMemberBlockSyntax {
1042
- let ( unexpectedBeforeLBrace, lbrace) = self . expect ( . leftBrace)
1091
+ guard let lBraceHandle = canRecoverTo ( . leftBrace) else {
1092
+ return RawMemberBlockSyntax (
1093
+ leftBrace: self . missingToken ( . leftBrace) ,
1094
+ members: RawMemberBlockItemListSyntax ( elements: [ ] , arena: self . arena) ,
1095
+ rightBrace: consume ( if: TokenSpec ( . rightBrace, allowAtStartOfLine: false ) ) ?? self . missingToken ( . rightBrace) ,
1096
+ arena: arena
1097
+ )
1098
+ }
1099
+ let ( unexpectedBeforeLBrace, lbrace) = self . eat ( lBraceHandle)
1043
1100
let members = parseMemberDeclList ( )
1044
1101
let ( unexpectedBeforeRBrace, rbrace) = self . expectRightBrace ( leftBrace: lbrace, introducer: introducer)
1045
1102
@@ -2322,4 +2379,57 @@ extension Parser {
2322
2379
arena: self . arena
2323
2380
)
2324
2381
}
2382
+
2383
+ mutating func parseUnexpectedCodeDeclaration(
2384
+ isAtTopLevel: Bool ,
2385
+ allowInitDecl: Bool ,
2386
+ requiresDecl: Bool ,
2387
+ skipToDeclOnly: Bool ,
2388
+ ) -> RawUnexpectedCodeDeclSyntax {
2389
+ let numTokensToSkip = withLookahead { ( lookahead) -> Int in
2390
+ while !lookahead. at ( . endOfFile, . semicolon) {
2391
+ if lookahead. at ( . poundElse, . poundElseif, . poundEndif) {
2392
+ break ;
2393
+ }
2394
+ if !isAtTopLevel && lookahead. at ( . rightBrace) {
2395
+ break ;
2396
+ }
2397
+ lookahead. skipSingle ( )
2398
+
2399
+ if lookahead. at ( . poundIf) {
2400
+ break
2401
+ }
2402
+ if lookahead. at ( . poundSourceLocation) {
2403
+ break
2404
+ }
2405
+ if lookahead. atStartOfDeclaration (
2406
+ isAtTopLevel: isAtTopLevel,
2407
+ allowInitDecl: allowInitDecl,
2408
+ requiresDecl: requiresDecl
2409
+ ) {
2410
+ break
2411
+ }
2412
+
2413
+ if skipToDeclOnly {
2414
+ continue
2415
+ }
2416
+ if lookahead. atStartOfStatement ( preferExpr: false ) {
2417
+ break
2418
+ }
2419
+ // Recover to an expression only if it's on the next line.
2420
+ if lookahead. currentToken. isAtStartOfLine && lookahead. atStartOfExpression ( ) {
2421
+ break
2422
+ }
2423
+ }
2424
+ return lookahead. tokensConsumed
2425
+ }
2426
+ var unexpectedTokens = [ RawSyntax] ( )
2427
+ for _ in 0 ..< numTokensToSkip {
2428
+ unexpectedTokens. append ( RawSyntax ( self . consumeAnyTokenWithoutAdjustingNestingLevel ( ) ) )
2429
+ }
2430
+ return RawUnexpectedCodeDeclSyntax (
2431
+ unexpectedCode: RawUnexpectedNodesSyntax ( elements: unexpectedTokens, arena: self . arena) ,
2432
+ arena: arena
2433
+ )
2434
+ }
2325
2435
}
0 commit comments