Skip to content

Commit 47a8dcd

Browse files
committed
Parse versions as three integer tokens
Previously, internals from the lexer leaked through by representing the major and minor part of the version as a float literal. Also, we accepted non-decimal numbers (eg. hex) for version number, which we don’t want. Fixes #1434 rdar://107152155
1 parent 39b3336 commit 47a8dcd

File tree

6 files changed

+323
-114
lines changed

6 files changed

+323
-114
lines changed

CodeGeneration/Sources/SyntaxSupport/AvailabilityNodes.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,21 @@ public let AVAILABILITY_NODES: [Node] = [
128128
kind: "Syntax",
129129
children: [
130130
Child(
131-
name: "MajorMinor",
132-
kind: .token(choices: [.token(tokenKind: "IntegerLiteralToken"), .token(tokenKind: "FloatingLiteralToken")]),
133-
description: "In case the version consists only of the major version, an integer literal that specifies the major version. In case the version consists of major and minor version number, a floating literal in which the decimal part is interpreted as the minor version."
131+
name: "Major",
132+
kind: .token(choices: [.token(tokenKind: "IntegerLiteralToken")]),
133+
description: "The major version."
134+
),
135+
Child(
136+
name: "MinorPeriod",
137+
kind: .token(choices: [.token(tokenKind: "PeriodToken")]),
138+
description: "If the version contains a minor number, the period separating the major from the minor number.",
139+
isOptional: true
140+
),
141+
Child(
142+
name: "Minor",
143+
kind: .token(choices: [.token(tokenKind: "IntegerLiteralToken")]),
144+
description: "The minor version if specified.",
145+
isOptional: true
134146
),
135147
Child(
136148
name: "PatchPeriod",
@@ -139,7 +151,7 @@ public let AVAILABILITY_NODES: [Node] = [
139151
isOptional: true
140152
),
141153
Child(
142-
name: "PatchVersion",
154+
name: "Patch",
143155
kind: .token(choices: [.token(tokenKind: "IntegerLiteralToken")]),
144156
description: "The patch version if specified.",
145157
isOptional: true

Sources/SwiftParser/Availability.swift

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,18 @@ extension Parser {
241241
)
242242
}
243243

244+
/// If the next token is an integer literal only consisting of the digits 0-9
245+
/// consume and return it, otherwise return a missing integer token.
246+
private mutating func expectDecimalIntegerWithoutRecovery() -> RawTokenSyntax {
247+
guard self.at(.integerLiteral) else {
248+
return missingToken(.integerLiteral, text: nil)
249+
}
250+
guard self.currentToken.tokenText.allSatisfy({ Unicode.Scalar($0).isDigit }) else {
251+
return missingToken(.integerLiteral, text: nil)
252+
}
253+
return self.consumeAnyToken()
254+
}
255+
244256
/// Parse a dot-separated list of version numbers.
245257
///
246258
/// Grammar
@@ -250,31 +262,43 @@ extension Parser {
250262
/// platform-version → decimal-digits '.' decimal-digits
251263
/// platform-version → decimal-digits '.' decimal-digits '.' decimal-digits
252264
mutating func parseVersionTuple() -> RawVersionTupleSyntax {
253-
let (unexpectedBeforeMajorMinor, majorMinor) = self.expect(.integerLiteral, .floatingLiteral, default: .integerLiteral)
254-
let patchPeriod: RawTokenSyntax?
255-
let unexpectedBeforePatch: RawUnexpectedNodesSyntax?
256-
let patch: RawTokenSyntax?
257-
if majorMinor.tokenKind == .floatingLiteral {
258-
patchPeriod = self.consume(if: .period)
259-
if patchPeriod != nil {
260-
(unexpectedBeforePatch, patch) = self.expect(.integerLiteral)
265+
if self.at(.floatingLiteral),
266+
let periodIndex = self.currentToken.tokenText.firstIndex(of: UInt8(ascii: ".")),
267+
self.currentToken.tokenText[0..<periodIndex].allSatisfy({ Unicode.Scalar($0).isDigit })
268+
{
269+
// The lexer generates a float literal '1.2' for the major and minor version.
270+
// Split it into two integers if possible
271+
let major = self.consumePrefix(SyntaxText(rebasing: self.currentToken.tokenText[0..<periodIndex]), as: .integerLiteral)
272+
let (unexpectedBeforeMinorPeriod, minorPeriod) = self.expect(.period)
273+
let minor = self.expectDecimalIntegerWithoutRecovery()
274+
let patchPeriod: RawTokenSyntax?
275+
let patch: RawTokenSyntax?
276+
if let period = self.consume(if: .period) {
277+
patchPeriod = period
278+
patch = self.expectDecimalIntegerWithoutRecovery()
261279
} else {
262-
unexpectedBeforePatch = nil
280+
patchPeriod = nil
263281
patch = nil
264282
}
283+
return RawVersionTupleSyntax(
284+
major: major,
285+
unexpectedBeforeMinorPeriod,
286+
minorPeriod: minorPeriod,
287+
minor: minor,
288+
patchPeriod: patchPeriod,
289+
patch: patch,
290+
arena: self.arena
291+
)
265292
} else {
266-
patchPeriod = nil
267-
unexpectedBeforePatch = nil
268-
patch = nil
293+
let major = self.expectDecimalIntegerWithoutRecovery()
294+
return RawVersionTupleSyntax(
295+
major: major,
296+
minorPeriod: nil,
297+
minor: nil,
298+
patchPeriod: nil,
299+
patch: nil,
300+
arena: self.arena
301+
)
269302
}
270-
271-
return RawVersionTupleSyntax(
272-
unexpectedBeforeMajorMinor,
273-
majorMinor: majorMinor,
274-
patchPeriod: patchPeriod,
275-
unexpectedBeforePatch,
276-
patchVersion: patch,
277-
arena: self.arena
278-
)
279303
}
280304
}

Sources/SwiftSyntax/generated/raw/RawSyntaxNodes.swift

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21031,56 +21031,80 @@ public struct RawVersionTupleSyntax: RawSyntaxNodeProtocol {
2103121031
}
2103221032

2103321033
public init(
21034-
_ unexpectedBeforeMajorMinor: RawUnexpectedNodesSyntax? = nil,
21035-
majorMinor: RawTokenSyntax,
21036-
_ unexpectedBetweenMajorMinorAndPatchPeriod: RawUnexpectedNodesSyntax? = nil,
21034+
_ unexpectedBeforeMajor: RawUnexpectedNodesSyntax? = nil,
21035+
major: RawTokenSyntax,
21036+
_ unexpectedBetweenMajorAndMinorPeriod: RawUnexpectedNodesSyntax? = nil,
21037+
minorPeriod: RawTokenSyntax?,
21038+
_ unexpectedBetweenMinorPeriodAndMinor: RawUnexpectedNodesSyntax? = nil,
21039+
minor: RawTokenSyntax?,
21040+
_ unexpectedBetweenMinorAndPatchPeriod: RawUnexpectedNodesSyntax? = nil,
2103721041
patchPeriod: RawTokenSyntax?,
21038-
_ unexpectedBetweenPatchPeriodAndPatchVersion: RawUnexpectedNodesSyntax? = nil,
21039-
patchVersion: RawTokenSyntax?,
21040-
_ unexpectedAfterPatchVersion: RawUnexpectedNodesSyntax? = nil,
21042+
_ unexpectedBetweenPatchPeriodAndPatch: RawUnexpectedNodesSyntax? = nil,
21043+
patch: RawTokenSyntax?,
21044+
_ unexpectedAfterPatch: RawUnexpectedNodesSyntax? = nil,
2104121045
arena: __shared SyntaxArena
2104221046
) {
2104321047
let raw = RawSyntax.makeLayout(
21044-
kind: .versionTuple, uninitializedCount: 7, arena: arena) { layout in
21048+
kind: .versionTuple, uninitializedCount: 11, arena: arena) { layout in
2104521049
layout.initialize(repeating: nil)
21046-
layout[0] = unexpectedBeforeMajorMinor?.raw
21047-
layout[1] = majorMinor.raw
21048-
layout[2] = unexpectedBetweenMajorMinorAndPatchPeriod?.raw
21049-
layout[3] = patchPeriod?.raw
21050-
layout[4] = unexpectedBetweenPatchPeriodAndPatchVersion?.raw
21051-
layout[5] = patchVersion?.raw
21052-
layout[6] = unexpectedAfterPatchVersion?.raw
21050+
layout[0] = unexpectedBeforeMajor?.raw
21051+
layout[1] = major.raw
21052+
layout[2] = unexpectedBetweenMajorAndMinorPeriod?.raw
21053+
layout[3] = minorPeriod?.raw
21054+
layout[4] = unexpectedBetweenMinorPeriodAndMinor?.raw
21055+
layout[5] = minor?.raw
21056+
layout[6] = unexpectedBetweenMinorAndPatchPeriod?.raw
21057+
layout[7] = patchPeriod?.raw
21058+
layout[8] = unexpectedBetweenPatchPeriodAndPatch?.raw
21059+
layout[9] = patch?.raw
21060+
layout[10] = unexpectedAfterPatch?.raw
2105321061
}
2105421062
self.init(unchecked: raw)
2105521063
}
2105621064

21057-
public var unexpectedBeforeMajorMinor: RawUnexpectedNodesSyntax? {
21065+
public var unexpectedBeforeMajor: RawUnexpectedNodesSyntax? {
2105821066
layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:))
2105921067
}
2106021068

21061-
public var majorMinor: RawTokenSyntax {
21069+
public var major: RawTokenSyntax {
2106221070
layoutView.children[1].map(RawTokenSyntax.init(raw:))!
2106321071
}
2106421072

21065-
public var unexpectedBetweenMajorMinorAndPatchPeriod: RawUnexpectedNodesSyntax? {
21073+
public var unexpectedBetweenMajorAndMinorPeriod: RawUnexpectedNodesSyntax? {
2106621074
layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:))
2106721075
}
2106821076

21069-
public var patchPeriod: RawTokenSyntax? {
21077+
public var minorPeriod: RawTokenSyntax? {
2107021078
layoutView.children[3].map(RawTokenSyntax.init(raw:))
2107121079
}
2107221080

21073-
public var unexpectedBetweenPatchPeriodAndPatchVersion: RawUnexpectedNodesSyntax? {
21081+
public var unexpectedBetweenMinorPeriodAndMinor: RawUnexpectedNodesSyntax? {
2107421082
layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:))
2107521083
}
2107621084

21077-
public var patchVersion: RawTokenSyntax? {
21085+
public var minor: RawTokenSyntax? {
2107821086
layoutView.children[5].map(RawTokenSyntax.init(raw:))
2107921087
}
2108021088

21081-
public var unexpectedAfterPatchVersion: RawUnexpectedNodesSyntax? {
21089+
public var unexpectedBetweenMinorAndPatchPeriod: RawUnexpectedNodesSyntax? {
2108221090
layoutView.children[6].map(RawUnexpectedNodesSyntax.init(raw:))
2108321091
}
21092+
21093+
public var patchPeriod: RawTokenSyntax? {
21094+
layoutView.children[7].map(RawTokenSyntax.init(raw:))
21095+
}
21096+
21097+
public var unexpectedBetweenPatchPeriodAndPatch: RawUnexpectedNodesSyntax? {
21098+
layoutView.children[8].map(RawUnexpectedNodesSyntax.init(raw:))
21099+
}
21100+
21101+
public var patch: RawTokenSyntax? {
21102+
layoutView.children[9].map(RawTokenSyntax.init(raw:))
21103+
}
21104+
21105+
public var unexpectedAfterPatch: RawUnexpectedNodesSyntax? {
21106+
layoutView.children[10].map(RawUnexpectedNodesSyntax.init(raw:))
21107+
}
2108421108
}
2108521109

2108621110
@_spi(RawSyntax)

Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -227,12 +227,7 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
227227
case .accessPathComponent:
228228
assert(layout.count == 5)
229229
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
230-
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [
231-
.tokenKind(.identifier),
232-
.tokenKind(.binaryOperator),
233-
.tokenKind(.prefixOperator),
234-
.tokenKind(.postfixOperator)
235-
]))
230+
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier)]))
236231
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
237232
assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.period)]))
238233
assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self))
@@ -835,13 +830,7 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
835830
case .declName:
836831
assert(layout.count == 5)
837832
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
838-
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [
839-
.tokenKind(.identifier),
840-
.tokenKind(.binaryOperator),
841-
.keyword("init"),
842-
.keyword("self"),
843-
.keyword("Self")
844-
]))
833+
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier), .tokenKind(.prefixOperator), .keyword("init")]))
845834
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
846835
assertNoError(kind, 3, verify(layout[3], as: RawDeclNameArgumentsSyntax?.self))
847836
assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self))
@@ -962,7 +951,7 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
962951
case .differentiableAttributeArguments:
963952
assert(layout.count == 11)
964953
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
965-
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax?.self, tokenChoices: [.keyword("_forward"), .keyword("reverse"), .keyword("_linear")]))
954+
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax?.self, tokenChoices: [.keyword("forward"), .keyword("reverse"), .keyword("linear")]))
966955
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
967956
assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.comma)]))
968957
assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self))
@@ -1019,12 +1008,7 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
10191008
case .editorPlaceholderExpr:
10201009
assert(layout.count == 3)
10211010
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
1022-
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [
1023-
.tokenKind(.identifier),
1024-
.keyword("self"),
1025-
.keyword("Self"),
1026-
.keyword("init")
1027-
]))
1011+
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.identifier)]))
10281012
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
10291013
case .effectsArguments:
10301014
for (index, element) in layout.enumerated() {
@@ -1561,7 +1545,14 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
15611545
case .labeledSpecializeEntry:
15621546
assert(layout.count == 9)
15631547
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
1564-
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self))
1548+
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [
1549+
.tokenKind(.identifier),
1550+
.keyword("available"),
1551+
.keyword("exported"),
1552+
.keyword("kind"),
1553+
.keyword("spi"),
1554+
.keyword("spiModule")
1555+
]))
15651556
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
15661557
assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.colon)]))
15671558
assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self))
@@ -1786,7 +1777,7 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
17861777
case .objCSelectorPiece:
17871778
assert(layout.count == 5)
17881779
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
1789-
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax?.self))
1780+
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.identifier)]))
17901781
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
17911782
assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.colon)]))
17921783
assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self))
@@ -2077,10 +2068,9 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
20772068
assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self))
20782069
assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax.self, tokenChoices: [
20792070
.tokenKind(.identifier),
2080-
.keyword("self"),
2081-
.keyword("Self"),
2082-
.keyword("init"),
2083-
.tokenKind(.binaryOperator)
2071+
.tokenKind(.binaryOperator),
2072+
.tokenKind(.prefixOperator),
2073+
.tokenKind(.postfixOperator)
20842074
]))
20852075
assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self))
20862076
assertNoError(kind, 7, verify(layout[7], as: RawDeclNameArgumentsSyntax?.self))
@@ -2524,14 +2514,18 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
25242514
assertNoError(kind, 7, verify(layout[7], as: RawPatternBindingListSyntax.self))
25252515
assertNoError(kind, 8, verify(layout[8], as: RawUnexpectedNodesSyntax?.self))
25262516
case .versionTuple:
2527-
assert(layout.count == 7)
2517+
assert(layout.count == 11)
25282518
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
2529-
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.integerLiteral), .tokenKind(.floatingLiteral)]))
2519+
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self, tokenChoices: [.tokenKind(.integerLiteral)]))
25302520
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
25312521
assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.period)]))
25322522
assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self))
25332523
assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.integerLiteral)]))
25342524
assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self))
2525+
assertNoError(kind, 7, verify(layout[7], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.period)]))
2526+
assertNoError(kind, 8, verify(layout[8], as: RawUnexpectedNodesSyntax?.self))
2527+
assertNoError(kind, 9, verify(layout[9], as: RawTokenSyntax?.self, tokenChoices: [.tokenKind(.integerLiteral)]))
2528+
assertNoError(kind, 10, verify(layout[10], as: RawUnexpectedNodesSyntax?.self))
25352529
case .whereClause:
25362530
assert(layout.count == 5)
25372531
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))

0 commit comments

Comments
 (0)