Skip to content

Commit f9985dd

Browse files
authored
Merge pull request #1226 from ahoppen/ahoppen/no-tokenlist-for-availability
Remove `TokenList` as option for `AvailabilityArgument`
2 parents b2e2f82 + 6d6d5f4 commit f9985dd

File tree

12 files changed

+138
-204
lines changed

12 files changed

+138
-204
lines changed

CodeGeneration/Sources/SyntaxSupport/gyb_generated/AvailabilityNodes.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ public let AVAILABILITY_NODES: [Node] = [
3636
Child(name: "AvailabilityVersionRestriction",
3737
kind: "AvailabilityVersionRestriction"),
3838
Child(name: "AvailabilityLabeledArgument",
39-
kind: "AvailabilityLabeledArgument"),
40-
Child(name: "TokenList",
41-
kind: "TokenList")
39+
kind: "AvailabilityLabeledArgument")
4240
]),
4341
Child(name: "TrailingComma",
4442
kind: "CommaToken",
@@ -81,7 +79,7 @@ public let AVAILABILITY_NODES: [Node] = [
8179
]),
8280

8381
Node(name: "AvailabilityVersionRestriction",
84-
nameForDiagnostics: "availability argument",
82+
nameForDiagnostics: "version restriction",
8583
description: "An argument to `@available` that restricts the availability on acertain platform to a version, e.g. `iOS 10` or `swift 3.4`.",
8684
kind: "Syntax",
8785
children: [

Sources/SwiftParser/Attributes.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -220,11 +220,7 @@ extension Parser {
220220
switch DeclarationAttributeWithSpecialSyntax(lexeme: self.peek()) {
221221
case .available, ._spi_available:
222222
return parseAttribute(argumentMode: .required) { parser in
223-
if parser.peek().rawTokenKind == .integerLiteral || parser.peek().rawTokenKind == .floatingLiteral {
224-
return .availability(parser.parseAvailabilitySpecList())
225-
} else {
226-
return .availability(parser.parseExtendedAvailabilitySpecList())
227-
}
223+
return .availability(parser.parseAvailabilityArgumentSpecList())
228224
}
229225
case .differentiable:
230226
return parseAttribute(argumentMode: .required) { parser in
@@ -997,7 +993,7 @@ extension Parser {
997993
var platforms: [RawAvailabilityVersionRestrictionListEntrySyntax] = []
998994
var keepGoing: RawTokenSyntax?
999995
repeat {
1000-
let restriction = self.parseAvailabilityMacro()
996+
let restriction = self.parseAvailabilityMacro(allowStarAsVersionNumber: true)
1001997
keepGoing = self.consume(if: .comma)
1002998
platforms.append(
1003999
RawAvailabilityVersionRestrictionListEntrySyntax(

Sources/SwiftParser/Availability.swift

Lines changed: 87 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -48,28 +48,6 @@ extension Parser {
4848
arena: self.arena
4949
)
5050
)
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-
}
7351
} while keepGoing != nil && availablityArgumentProgress.evaluate(currentToken)
7452
}
7553

@@ -84,6 +62,8 @@ extension Parser {
8462
case obsoleted
8563
case unavailable
8664
case noasync
65+
case star
66+
case identifier
8767

8868
init?(lexeme: Lexer.Lexeme) {
8969
switch lexeme {
@@ -94,6 +74,8 @@ extension Parser {
9474
case RawTokenKindMatch(.obsoleted): self = .obsoleted
9575
case RawTokenKindMatch(.unavailable): self = .unavailable
9676
case RawTokenKindMatch(.noasync): self = .noasync
77+
case RawTokenKindMatch(.binaryOperator) where lexeme.tokenText == "*": self = .star
78+
case RawTokenKindMatch(.identifier): self = .identifier
9779
default: return nil
9880
}
9981
}
@@ -107,100 +89,94 @@ extension Parser {
10789
case .obsoleted: return .keyword(.obsoleted)
10890
case .unavailable: return .keyword(.unavailable)
10991
case .noasync: return .keyword(.noasync)
92+
case .star: return .binaryOperator
93+
case .identifier: return .identifier
11094
}
11195
}
11296
}
11397

114-
mutating func parseExtendedAvailabilitySpecList() -> RawAvailabilitySpecListSyntax {
98+
mutating func parseAvailabilityArgumentSpecList() -> RawAvailabilitySpecListSyntax {
11599
var elements = [RawAvailabilityArgumentSyntax]()
100+
var keepGoing: RawTokenSyntax? = nil
116101

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()
127112

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
148120
)
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) {
153139
let version = self.parseVersionTuple()
154140
entry = .availabilityLabeledArgument(
155141
RawAvailabilityLabeledArgumentSyntax(
156142
label: argumentLabel,
157-
unexpectedBeforeColon,
158143
colon: colon,
159144
value: .version(version),
160145
arena: self.arena
161146
)
162147
)
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()
192166
}
167+
case nil:
168+
break LOOP
169+
}
193170

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
201177
)
202-
}
203-
}
178+
)
179+
} while keepGoing != nil && loopProgressCondition.evaluate(currentToken)
204180
return RawAvailabilitySpecListSyntax(elements: elements, arena: self.arena)
205181
}
206182

@@ -218,50 +194,7 @@ extension Parser {
218194
return .token(star)
219195
}
220196

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())
265198
}
266199

267200
/// Parse an availability macro.
@@ -272,19 +205,28 @@ extension Parser {
272205
/// =======
273206
///
274207
/// 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+
}
277220

278221
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]) {
282223
version = self.parseVersionTuple()
283224
} else {
284225
version = nil
285226
}
286227

287228
return RawAvailabilityVersionRestrictionSyntax(
229+
unexpectedBeforePlatform,
288230
platform: platform,
289231
version: version,
290232
arena: self.arena

Sources/SwiftSyntax/Raw/gyb_generated/RawSyntaxNodes.swift

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18086,18 +18086,16 @@ public struct RawAvailabilityArgumentSyntax: RawSyntaxNodeProtocol {
1808618086
case `token`(RawTokenSyntax)
1808718087
case `availabilityVersionRestriction`(RawAvailabilityVersionRestrictionSyntax)
1808818088
case `availabilityLabeledArgument`(RawAvailabilityLabeledArgumentSyntax)
18089-
case `tokenList`(RawTokenListSyntax)
1809018089

1809118090
public static func isKindOf(_ raw: RawSyntax) -> Bool {
18092-
return RawTokenSyntax.isKindOf(raw) || RawAvailabilityVersionRestrictionSyntax.isKindOf(raw) || RawAvailabilityLabeledArgumentSyntax.isKindOf(raw) || RawTokenListSyntax.isKindOf(raw)
18091+
return RawTokenSyntax.isKindOf(raw) || RawAvailabilityVersionRestrictionSyntax.isKindOf(raw) || RawAvailabilityLabeledArgumentSyntax.isKindOf(raw)
1809318092
}
1809418093

1809518094
public var raw: RawSyntax {
1809618095
switch self {
1809718096
case .token(let node): return node.raw
1809818097
case .availabilityVersionRestriction(let node): return node.raw
1809918098
case .availabilityLabeledArgument(let node): return node.raw
18100-
case .tokenList(let node): return node.raw
1810118099
}
1810218100
}
1810318101

@@ -18114,10 +18112,6 @@ public struct RawAvailabilityArgumentSyntax: RawSyntaxNodeProtocol {
1811418112
self = .availabilityLabeledArgument(node)
1811518113
return
1811618114
}
18117-
if let node = RawTokenListSyntax(other) {
18118-
self = .tokenList(node)
18119-
return
18120-
}
1812118115
return nil
1812218116
}
1812318117
}

Sources/SwiftSyntax/Raw/gyb_generated/RawSyntaxValidation.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2637,7 +2637,6 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
26372637
verify(layout[1], as: RawSyntax.self),
26382638
verify(layout[1], as: RawSyntax.self),
26392639
verify(layout[1], as: RawSyntax.self),
2640-
verify(layout[1], as: RawSyntax.self),
26412640
])
26422641
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
26432642
assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax?.self))

Sources/SwiftSyntax/generated/Misc.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ extension SyntaxKind {
865865
case .availabilityVersionRestrictionList:
866866
return "version list"
867867
case .availabilityVersionRestriction:
868-
return "availability argument"
868+
return "version restriction"
869869
case .awaitExpr:
870870
return "'await' expression"
871871
case .backDeployAttributeSpecList:

0 commit comments

Comments
 (0)