@@ -48,28 +48,6 @@ extension Parser {
48
48
arena: self . arena
49
49
)
50
50
)
51
-
52
- // Before continuing to parse the next specification, we check that it's
53
- // also in the shorthand syntax and recover from it.
54
- if keepGoing != nil ,
55
- let ( _, handle) = self . at ( anyIn: AvailabilityArgumentKind . self)
56
- {
57
- var tokens = [ RawTokenSyntax] ( )
58
- tokens. append ( self . eat ( handle) )
59
- var recoveryProgress = LoopProgressCondition ( )
60
- while !self . at ( any: [ . eof, . comma, . rightParen] ) && recoveryProgress. evaluate ( currentToken) {
61
- tokens. append ( self . consumeAnyToken ( ) )
62
- }
63
- let syntax = RawTokenListSyntax ( elements: tokens, arena: self . arena)
64
- keepGoing = self . consume ( if: . comma)
65
- elements. append (
66
- RawAvailabilityArgumentSyntax (
67
- entry: . tokenList( syntax) ,
68
- trailingComma: keepGoing,
69
- arena: self . arena
70
- )
71
- )
72
- }
73
51
} while keepGoing != nil && availablityArgumentProgress. evaluate ( currentToken)
74
52
}
75
53
@@ -84,6 +62,8 @@ extension Parser {
84
62
case obsoleted
85
63
case unavailable
86
64
case noasync
65
+ case star
66
+ case identifier
87
67
88
68
init ? ( lexeme: Lexer . Lexeme ) {
89
69
switch lexeme {
@@ -94,6 +74,8 @@ extension Parser {
94
74
case RawTokenKindMatch ( . obsoleted) : self = . obsoleted
95
75
case RawTokenKindMatch ( . unavailable) : self = . unavailable
96
76
case RawTokenKindMatch ( . noasync) : self = . noasync
77
+ case RawTokenKindMatch ( . binaryOperator) where lexeme. tokenText == " * " : self = . star
78
+ case RawTokenKindMatch ( . identifier) : self = . identifier
97
79
default : return nil
98
80
}
99
81
}
@@ -107,100 +89,94 @@ extension Parser {
107
89
case . obsoleted: return . keyword( . obsoleted)
108
90
case . unavailable: return . keyword( . unavailable)
109
91
case . noasync: return . keyword( . noasync)
92
+ case . star: return . binaryOperator
93
+ case . identifier: return . identifier
110
94
}
111
95
}
112
96
}
113
97
114
- mutating func parseExtendedAvailabilitySpecList ( ) -> RawAvailabilitySpecListSyntax {
98
+ mutating func parseAvailabilityArgumentSpecList ( ) -> RawAvailabilitySpecListSyntax {
115
99
var elements = [ RawAvailabilityArgumentSyntax] ( )
100
+ var keepGoing : RawTokenSyntax ? = nil
116
101
117
- // Parse the platform from the first element.
118
- let platform = self . consumeAnyToken ( )
119
- var keepGoing : RawTokenSyntax ? = self . consume ( if : . comma )
120
- elements . append (
121
- RawAvailabilityArgumentSyntax (
122
- entry : . token ( platform ) ,
123
- trailingComma : keepGoing ,
124
- arena : self . arena
125
- )
126
- )
102
+ var loopProgressCondition = LoopProgressCondition ( )
103
+ LOOP: repeat {
104
+ let entry : RawAvailabilityArgumentSyntax . Entry
105
+ switch self . at ( anyIn : AvailabilityArgumentKind . self ) {
106
+ case ( . message , let handle ) ? ,
107
+ ( . renamed , let handle ) ? :
108
+ let argumentLabel = self . eat ( handle )
109
+ let ( unexpectedBeforeColon , colon ) = self . expect ( . colon )
110
+ // FIXME: Make sure this is a string literal with no interpolation.
111
+ let stringValue = self . consumeAnyToken ( )
127
112
128
- do {
129
- var loopProgressCondition = LoopProgressCondition ( )
130
- while keepGoing != nil && loopProgressCondition. evaluate ( currentToken) {
131
- let entry : RawAvailabilityArgumentSyntax . Entry
132
- switch self . at ( anyIn: AvailabilityArgumentKind . self) {
133
- case ( . message, let handle) ? ,
134
- ( . renamed, let handle) ? :
135
- let argumentLabel = self . eat ( handle)
136
- let ( unexpectedBeforeColon, colon) = self . expect ( . colon)
137
- // FIXME: Make sure this is a string literal with no interpolation.
138
- let stringValue = self . consumeAnyToken ( )
139
-
140
- entry = . availabilityLabeledArgument(
141
- RawAvailabilityLabeledArgumentSyntax (
142
- label: argumentLabel,
143
- unexpectedBeforeColon,
144
- colon: colon,
145
- value: . string( stringValue) ,
146
- arena: self . arena
147
- )
113
+ entry = . availabilityLabeledArgument(
114
+ RawAvailabilityLabeledArgumentSyntax (
115
+ label: argumentLabel,
116
+ unexpectedBeforeColon,
117
+ colon: colon,
118
+ value: . string( stringValue) ,
119
+ arena: self . arena
148
120
)
149
- case ( . introduced, let handle) ? ,
150
- ( . obsoleted, let handle) ? :
151
- let argumentLabel = self . eat ( handle)
152
- let ( unexpectedBeforeColon, colon) = self . expect ( . colon)
121
+ )
122
+ case ( . introduced, let handle) ? ,
123
+ ( . obsoleted, let handle) ? :
124
+ let argumentLabel = self . eat ( handle)
125
+ let ( unexpectedBeforeColon, colon) = self . expect ( . colon)
126
+ let version = self . parseVersionTuple ( )
127
+ entry = . availabilityLabeledArgument(
128
+ RawAvailabilityLabeledArgumentSyntax (
129
+ label: argumentLabel,
130
+ unexpectedBeforeColon,
131
+ colon: colon,
132
+ value: . version( version) ,
133
+ arena: self . arena
134
+ )
135
+ )
136
+ case ( . deprecated, let handle) ? :
137
+ let argumentLabel = self . eat ( handle)
138
+ if let colon = self . consume ( if: . colon) {
153
139
let version = self . parseVersionTuple ( )
154
140
entry = . availabilityLabeledArgument(
155
141
RawAvailabilityLabeledArgumentSyntax (
156
142
label: argumentLabel,
157
- unexpectedBeforeColon,
158
143
colon: colon,
159
144
value: . version( version) ,
160
145
arena: self . arena
161
146
)
162
147
)
163
- case ( . deprecated, let handle) ? :
164
- let argumentLabel = self . eat ( handle)
165
- if let colon = self . consume ( if: . colon) {
166
- let version = self . parseVersionTuple ( )
167
- entry = . availabilityLabeledArgument(
168
- RawAvailabilityLabeledArgumentSyntax (
169
- label: argumentLabel,
170
- colon: colon,
171
- value: . version( version) ,
172
- arena: self . arena
173
- )
174
- )
175
- } else {
176
- entry = . token( argumentLabel)
177
- }
178
- case ( . unavailable, let handle) ? ,
179
- ( . noasync, let handle) ? :
180
- let argument = self . eat ( handle)
181
- // FIXME: Can we model this in SwiftSyntax by making the
182
- // 'labeled' argument part optional?
183
- entry = . token( argument)
184
- case nil :
185
- // Not sure what this label is but, let's just eat it and
186
- // keep going.
187
- var tokens = [ RawTokenSyntax] ( )
188
- while !self . at ( any: [ . eof, . comma, . rightParen] ) {
189
- tokens. append ( self . consumeAnyToken ( ) )
190
- }
191
- entry = . tokenList( RawTokenListSyntax ( elements: tokens, arena: self . arena) )
148
+ } else {
149
+ entry = . token( argumentLabel)
150
+ }
151
+ case ( . unavailable, let handle) ? ,
152
+ ( . noasync, let handle) ? :
153
+ let argument = self . eat ( handle)
154
+ // FIXME: Can we model this in SwiftSyntax by making the
155
+ // 'labeled' argument part optional?
156
+ entry = . token( argument)
157
+ case ( . star, _) ? :
158
+ entry = self . parseAvailabilitySpec ( )
159
+ case ( . identifier, let handle) ? :
160
+ if self . peek ( ) . rawTokenKind == . comma {
161
+ // An argument like `_iOS13Aligned` that isn't followed by a version.
162
+ let version = self . eat ( handle)
163
+ entry = . token( version)
164
+ } else {
165
+ entry = self . parseAvailabilitySpec ( )
192
166
}
167
+ case nil :
168
+ break LOOP
169
+ }
193
170
194
- keepGoing = self . consume ( if: . comma)
195
- elements. append (
196
- RawAvailabilityArgumentSyntax (
197
- entry: entry,
198
- trailingComma: keepGoing,
199
- arena: self . arena
200
- )
171
+ keepGoing = self . consume ( if: . comma)
172
+ elements. append (
173
+ RawAvailabilityArgumentSyntax (
174
+ entry: entry,
175
+ trailingComma: keepGoing,
176
+ arena: self . arena
201
177
)
202
- }
203
- }
178
+ )
179
+ } while keepGoing != nil && loopProgressCondition . evaluate ( currentToken )
204
180
return RawAvailabilitySpecListSyntax ( elements: elements, arena: self . arena)
205
181
}
206
182
@@ -218,50 +194,7 @@ extension Parser {
218
194
return . token( star)
219
195
}
220
196
221
- if self . at ( any: [ . identifier, . wildcard] ) {
222
- if self . at ( . keyword( . swift) ) || self . at ( . keyword( . _PackageDescription) ) {
223
- return . availabilityVersionRestriction( self . parsePlatformAgnosticVersionConstraintSpec ( ) )
224
- }
225
- }
226
-
227
- return . availabilityVersionRestriction( self . parsePlatformVersionConstraintSpec ( ) )
228
- }
229
-
230
- mutating func parsePlatformAgnosticVersionConstraintSpec( ) -> RawAvailabilityVersionRestrictionSyntax {
231
- let ( unexpectedBeforePlatform, platform) = self . expectAny ( [ . identifier, . wildcard] , default: . identifier)
232
- let version = self . parseVersionTuple ( )
233
- return RawAvailabilityVersionRestrictionSyntax (
234
- unexpectedBeforePlatform,
235
- platform: platform,
236
- version: version,
237
- arena: self . arena
238
- )
239
- }
240
-
241
- /// Parse a platform-specific version constraint.
242
- ///
243
- /// The grammar calls out Apple-specific names, even though the Swift compiler
244
- /// will accept any identifier here. The compiler will diagnose usages of platforms it
245
- /// doesn't know about later.
246
- ///
247
- /// Grammar
248
- /// =======
249
- ///
250
- /// platform-name → iOS | iOSApplicationExtension
251
- /// platform-name → macOS | macOSApplicationExtension
252
- /// platform-name → macCatalyst | macCatalystApplicationExtension
253
- /// platform-name → watchOS
254
- /// platform-name → tvOS
255
- mutating func parsePlatformVersionConstraintSpec( ) -> RawAvailabilityVersionRestrictionSyntax {
256
- // Register the platform name as a keyword token.
257
- let ( unexpectedBeforePlatform, plaform) = self . expect ( . identifier)
258
- let version = self . parseVersionTuple ( )
259
- return RawAvailabilityVersionRestrictionSyntax (
260
- unexpectedBeforePlatform,
261
- platform: plaform,
262
- version: version,
263
- arena: self . arena
264
- )
197
+ return . availabilityVersionRestriction( self . parseAvailabilityMacro ( ) )
265
198
}
266
199
267
200
/// Parse an availability macro.
@@ -272,19 +205,28 @@ extension Parser {
272
205
/// =======
273
206
///
274
207
/// availability-argument → macro-name platform-version
275
- mutating func parseAvailabilityMacro( ) -> RawAvailabilityVersionRestrictionSyntax {
276
- let platform = self . consumeAnyToken ( )
208
+ ///
209
+ /// If `allowStarAsVersionNumber` is `true`, versions like `* 13.0` are accepted.
210
+ /// This is to match the behavior of `@_originallyDefinedIn` in the old parser that accepted such versions
211
+ mutating func parseAvailabilityMacro( allowStarAsVersionNumber: Bool = false ) -> RawAvailabilityVersionRestrictionSyntax {
212
+ let unexpectedBeforePlatform : RawUnexpectedNodesSyntax ?
213
+ let platform : RawTokenSyntax
214
+ if allowStarAsVersionNumber, self . atContextualPunctuator ( " * " ) {
215
+ unexpectedBeforePlatform = nil
216
+ platform = self . consumeAnyToken ( remapping: . identifier)
217
+ } else {
218
+ ( unexpectedBeforePlatform, platform) = self . expect ( . identifier)
219
+ }
277
220
278
221
let version : RawVersionTupleSyntax ?
279
- if self . at ( . integerLiteral) {
280
- version = self . parseVersionTuple ( )
281
- } else if self . at ( . floatingLiteral) {
222
+ if self . at ( any: [ . integerLiteral, . floatingLiteral] ) {
282
223
version = self . parseVersionTuple ( )
283
224
} else {
284
225
version = nil
285
226
}
286
227
287
228
return RawAvailabilityVersionRestrictionSyntax (
229
+ unexpectedBeforePlatform,
288
230
platform: platform,
289
231
version: version,
290
232
arena: self . arena
0 commit comments