@@ -16,18 +16,21 @@ extension Parser {
16
16
private enum IfConfigContinuationClauseStartKeyword : TokenSpecSet {
17
17
case poundElseifKeyword
18
18
case poundElseKeyword
19
+ case pound
19
20
20
21
var spec : TokenSpec {
21
22
switch self {
22
23
case . poundElseifKeyword: return . poundElseifKeyword
23
24
case . poundElseKeyword: return . poundElseKeyword
25
+ case . pound: return TokenSpec ( . pound, recoveryPrecedence: . openingPoundIf)
24
26
}
25
27
}
26
28
27
29
init ? ( lexeme: Lexer . Lexeme ) {
28
30
switch PrepareForKeywordMatch ( lexeme) {
29
31
case TokenSpec ( . poundElseifKeyword) : self = . poundElseifKeyword
30
32
case TokenSpec ( . poundElseKeyword) : self = . poundElseKeyword
33
+ case TokenSpec ( . pound) : self = . pound
31
34
default : return nil
32
35
}
33
36
}
@@ -106,29 +109,54 @@ extension Parser {
106
109
while let poundIfHandle = firstIteration ? self . canRecoverTo ( . poundIfKeyword) : self . canRecoverTo ( anyIn: IfConfigContinuationClauseStartKeyword . self) ? . handle,
107
110
loopProgress. evaluate ( self . currentToken)
108
111
{
109
- var ( unexpectedBeforePoundIf, poundIf) = self . eat ( poundIfHandle)
110
- firstIteration = false
111
- // Parse the condition.
112
+ var unexpectedBeforePound : RawUnexpectedNodesSyntax ?
113
+ var pound : RawTokenSyntax
112
114
let condition : RawExprSyntax ?
113
- switch poundIf. tokenKind {
114
- case . poundIfKeyword, . poundElseifKeyword:
115
+ var atElifTypo : Bool {
116
+ guard self . at ( TokenSpec ( . pound) ) , self . currentToken. trailingTriviaText. isEmpty else {
117
+ return false
118
+ }
119
+ let identifierSpec = TokenSpec ( . identifier, allowAtStartOfLine: false )
120
+ var lookahead = self . lookahead ( )
121
+ lookahead. consumeAnyToken ( )
122
+ guard lookahead. at ( identifierSpec) , lookahead. currentToken. tokenText == " elif " , lookahead. currentToken. leadingTriviaText. isEmpty else {
123
+ return false
124
+ }
125
+ lookahead. consumeAnyToken ( )
126
+ return lookahead. at ( identifierSpec)
127
+ }
128
+
129
+ if atElifTypo {
130
+ ( unexpectedBeforePound, pound) = self . eat ( poundIfHandle)
131
+ guard let identifier = self . consume ( if: TokenSpec ( . identifier, allowAtStartOfLine: false ) ) else {
132
+ preconditionFailure ( " The current token should be an identifier, guaranteed by the previous if statement " )
133
+ }
134
+ unexpectedBeforePound = RawUnexpectedNodesSyntax ( combining: unexpectedBeforePound, pound, identifier, arena: self . arena)
135
+ pound = self . missingToken ( . poundElseifKeyword)
115
136
condition = RawExprSyntax ( self . parseSequenceExpression ( . basic, forDirective: true ) )
116
- case . poundElseKeyword:
117
- if let ifToken = self . consume ( if: . init( . if, allowAtStartOfLine: false ) ) {
118
- unexpectedBeforePoundIf = RawUnexpectedNodesSyntax ( combining: unexpectedBeforePoundIf, poundIf, ifToken, arena: self . arena)
119
- poundIf = self . missingToken ( . poundElseifKeyword)
137
+ } else {
138
+ ( unexpectedBeforePound, pound) = self . eat ( poundIfHandle)
139
+ firstIteration = false
140
+ switch pound. tokenKind {
141
+ case . poundIfKeyword, . poundElseifKeyword:
120
142
condition = RawExprSyntax ( self . parseSequenceExpression ( . basic, forDirective: true ) )
121
- } else {
122
- condition = nil
143
+ case . poundElseKeyword:
144
+ if let ifToken = self . consume ( if: . init( . if, allowAtStartOfLine: false ) ) {
145
+ unexpectedBeforePound = RawUnexpectedNodesSyntax ( combining: unexpectedBeforePound, pound, ifToken, arena: self . arena)
146
+ pound = self . missingToken ( . poundElseifKeyword)
147
+ condition = RawExprSyntax ( self . parseSequenceExpression ( . basic, forDirective: true ) )
148
+ } else {
149
+ condition = nil
150
+ }
151
+ default :
152
+ preconditionFailure ( " The loop condition should guarantee that we are at one of these tokens " )
123
153
}
124
- default :
125
- preconditionFailure ( " The loop condition should guarantee that we are at one of these tokens " )
126
154
}
127
155
128
156
var elements = [ Element] ( )
129
157
do {
130
158
var elementsProgress = LoopProgressCondition ( )
131
- while !self . at ( . eof) && !self . at ( . poundElseKeyword, . poundElseifKeyword, . poundEndifKeyword) && elementsProgress. evaluate ( currentToken) {
159
+ while !self . at ( . eof) && !self . at ( . poundElseKeyword, . poundElseifKeyword, . poundEndifKeyword) && !atElifTypo && elementsProgress. evaluate ( currentToken) {
132
160
let newItemAtStartOfLine = self . currentToken. isAtStartOfLine
133
161
guard let element = parseElement ( & self , elements. isEmpty) , !element. isEmpty else {
134
162
break
@@ -142,8 +170,8 @@ extension Parser {
142
170
143
171
clauses. append (
144
172
RawIfConfigClauseSyntax (
145
- unexpectedBeforePoundIf ,
146
- poundKeyword: poundIf ,
173
+ unexpectedBeforePound ,
174
+ poundKeyword: pound ,
147
175
condition: condition,
148
176
elements: syntax ( & self , elements) ,
149
177
arena: self . arena
0 commit comments