18
18
/// After calling `consume(ifAnyFrom:)` we know which token we are positioned
19
19
/// at based on that function's return type. This handle allows consuming that
20
20
/// token.
21
- struct RecoveryConsumptionHandle {
21
+ @_spi ( RawSyntax)
22
+ public struct RecoveryConsumptionHandle {
22
23
var unexpectedTokens : Int
23
24
var tokenConsumptionHandle : TokenConsumptionHandle
24
25
}
@@ -36,7 +37,9 @@ extension Parser.Lookahead {
36
37
_ kinds: [ RawTokenKind ] ,
37
38
contextualKeywords: [ SyntaxText ] = [ ] ,
38
39
recoveryPrecedence: TokenPrecedence ? = nil
39
- ) -> Bool {
40
+ ) -> RecoveryConsumptionHandle ? {
41
+ let initialTokensConsumed = self . tokensConsumed
42
+
40
43
var precedences = kinds. map ( TokenPrecedence . init)
41
44
if !contextualKeywords. isEmpty {
42
45
precedences += [ TokenPrecedence ( . identifier) , TokenPrecedence ( . contextualKeyword) ]
@@ -49,22 +52,28 @@ extension Parser.Lookahead {
49
52
break
50
53
}
51
54
if self . at ( any: kinds, contextualKeywords: contextualKeywords) {
52
- return true
55
+ return RecoveryConsumptionHandle (
56
+ unexpectedTokens: self . tokensConsumed - initialTokensConsumed,
57
+ tokenConsumptionHandle: TokenConsumptionHandle (
58
+ tokenKind: self . currentToken. tokenKind,
59
+ remappedKind: self . at ( any: [ ] , contextualKeywords: contextualKeywords) ? . contextualKeyword : nil
60
+ )
61
+ )
53
62
}
54
63
let currentTokenPrecedence = TokenPrecedence ( self . currentToken. tokenKind)
55
64
if currentTokenPrecedence >= recoveryPrecedence {
56
65
break
57
66
}
58
67
self . consumeAnyToken ( )
59
68
if let closingDelimiter = currentTokenPrecedence. closingTokenKind {
60
- guard self . canRecoverTo ( [ closingDelimiter] ) else {
69
+ guard self . canRecoverTo ( [ closingDelimiter] ) != nil else {
61
70
break
62
71
}
63
72
self . eat ( closingDelimiter)
64
73
}
65
74
}
66
75
67
- return false
76
+ return nil
68
77
}
69
78
70
79
/// Checks if we can reach a token in `subset` by skipping tokens that have
@@ -76,6 +85,8 @@ extension Parser.Lookahead {
76
85
anyIn subset: Subset . Type ,
77
86
recoveryPrecedence: TokenPrecedence ? = nil
78
87
) -> ( Subset , RecoveryConsumptionHandle ) ? {
88
+ let initialTokensConsumed = self . tokensConsumed
89
+
79
90
assert ( !subset. allCases. isEmpty, " Subset must have at least one case " )
80
91
let recoveryPrecedence = recoveryPrecedence ?? subset. allCases. map ( {
81
92
if let precedence = $0. precedence {
@@ -84,8 +95,6 @@ extension Parser.Lookahead {
84
95
return TokenPrecedence ( $0. rawTokenKind)
85
96
}
86
97
} ) . min ( ) !
87
- let initialTokensConsumed = self . tokensConsumed
88
- assert ( !subset. allCases. isEmpty)
89
98
while !self . at ( . eof) {
90
99
if !recoveryPrecedence. shouldSkipOverNewlines,
91
100
self . currentToken. isAtStartOfLine {
@@ -103,7 +112,7 @@ extension Parser.Lookahead {
103
112
}
104
113
self . consumeAnyToken ( )
105
114
if let closingDelimiter = currentTokenPrecedence. closingTokenKind {
106
- guard self . canRecoverTo ( [ closingDelimiter] ) else {
115
+ guard self . canRecoverTo ( [ closingDelimiter] ) != nil else {
107
116
break
108
117
}
109
118
self . eat ( closingDelimiter)
0 commit comments