Skip to content

Commit cbf27d5

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 f340316 commit cbf27d5

File tree

6 files changed

+286
-67
lines changed

6 files changed

+286
-67
lines changed

CodeGeneration/Sources/SyntaxSupport/AvailabilityNodes.swift

Lines changed: 15 additions & 3 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 majro 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",

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+
patchVersion: 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+
patchVersion: 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: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19995,56 +19995,80 @@ public struct RawVersionTupleSyntax: RawSyntaxNodeProtocol {
1999519995
}
1999619996

1999719997
public init(
19998-
_ unexpectedBeforeMajorMinor: RawUnexpectedNodesSyntax? = nil,
19999-
majorMinor: RawTokenSyntax,
20000-
_ unexpectedBetweenMajorMinorAndPatchPeriod: RawUnexpectedNodesSyntax? = nil,
19998+
_ unexpectedBeforeMajor: RawUnexpectedNodesSyntax? = nil,
19999+
major: RawTokenSyntax,
20000+
_ unexpectedBetweenMajorAndMinorPeriod: RawUnexpectedNodesSyntax? = nil,
20001+
minorPeriod: RawTokenSyntax?,
20002+
_ unexpectedBetweenMinorPeriodAndMinor: RawUnexpectedNodesSyntax? = nil,
20003+
minor: RawTokenSyntax?,
20004+
_ unexpectedBetweenMinorAndPatchPeriod: RawUnexpectedNodesSyntax? = nil,
2000120005
patchPeriod: RawTokenSyntax?,
2000220006
_ unexpectedBetweenPatchPeriodAndPatchVersion: RawUnexpectedNodesSyntax? = nil,
2000320007
patchVersion: RawTokenSyntax?,
2000420008
_ unexpectedAfterPatchVersion: RawUnexpectedNodesSyntax? = nil,
2000520009
arena: __shared SyntaxArena
2000620010
) {
2000720011
let raw = RawSyntax.makeLayout(
20008-
kind: .versionTuple, uninitializedCount: 7, arena: arena) { layout in
20012+
kind: .versionTuple, uninitializedCount: 11, arena: arena) { layout in
2000920013
layout.initialize(repeating: nil)
20010-
layout[0] = unexpectedBeforeMajorMinor?.raw
20011-
layout[1] = majorMinor.raw
20012-
layout[2] = unexpectedBetweenMajorMinorAndPatchPeriod?.raw
20013-
layout[3] = patchPeriod?.raw
20014-
layout[4] = unexpectedBetweenPatchPeriodAndPatchVersion?.raw
20015-
layout[5] = patchVersion?.raw
20016-
layout[6] = unexpectedAfterPatchVersion?.raw
20014+
layout[0] = unexpectedBeforeMajor?.raw
20015+
layout[1] = major.raw
20016+
layout[2] = unexpectedBetweenMajorAndMinorPeriod?.raw
20017+
layout[3] = minorPeriod?.raw
20018+
layout[4] = unexpectedBetweenMinorPeriodAndMinor?.raw
20019+
layout[5] = minor?.raw
20020+
layout[6] = unexpectedBetweenMinorAndPatchPeriod?.raw
20021+
layout[7] = patchPeriod?.raw
20022+
layout[8] = unexpectedBetweenPatchPeriodAndPatchVersion?.raw
20023+
layout[9] = patchVersion?.raw
20024+
layout[10] = unexpectedAfterPatchVersion?.raw
2001720025
}
2001820026
self.init(raw: raw)
2001920027
}
2002020028

20021-
public var unexpectedBeforeMajorMinor: RawUnexpectedNodesSyntax? {
20029+
public var unexpectedBeforeMajor: RawUnexpectedNodesSyntax? {
2002220030
layoutView.children[0].map(RawUnexpectedNodesSyntax.init(raw:))
2002320031
}
2002420032

20025-
public var majorMinor: RawTokenSyntax {
20033+
public var major: RawTokenSyntax {
2002620034
layoutView.children[1].map(RawTokenSyntax.init(raw:))!
2002720035
}
2002820036

20029-
public var unexpectedBetweenMajorMinorAndPatchPeriod: RawUnexpectedNodesSyntax? {
20037+
public var unexpectedBetweenMajorAndMinorPeriod: RawUnexpectedNodesSyntax? {
2003020038
layoutView.children[2].map(RawUnexpectedNodesSyntax.init(raw:))
2003120039
}
2003220040

20033-
public var patchPeriod: RawTokenSyntax? {
20041+
public var minorPeriod: RawTokenSyntax? {
2003420042
layoutView.children[3].map(RawTokenSyntax.init(raw:))
2003520043
}
2003620044

20037-
public var unexpectedBetweenPatchPeriodAndPatchVersion: RawUnexpectedNodesSyntax? {
20045+
public var unexpectedBetweenMinorPeriodAndMinor: RawUnexpectedNodesSyntax? {
2003820046
layoutView.children[4].map(RawUnexpectedNodesSyntax.init(raw:))
2003920047
}
2004020048

20041-
public var patchVersion: RawTokenSyntax? {
20049+
public var minor: RawTokenSyntax? {
2004220050
layoutView.children[5].map(RawTokenSyntax.init(raw:))
2004320051
}
2004420052

20045-
public var unexpectedAfterPatchVersion: RawUnexpectedNodesSyntax? {
20053+
public var unexpectedBetweenMinorAndPatchPeriod: RawUnexpectedNodesSyntax? {
2004620054
layoutView.children[6].map(RawUnexpectedNodesSyntax.init(raw:))
2004720055
}
20056+
20057+
public var patchPeriod: RawTokenSyntax? {
20058+
layoutView.children[7].map(RawTokenSyntax.init(raw:))
20059+
}
20060+
20061+
public var unexpectedBetweenPatchPeriodAndPatchVersion: RawUnexpectedNodesSyntax? {
20062+
layoutView.children[8].map(RawUnexpectedNodesSyntax.init(raw:))
20063+
}
20064+
20065+
public var patchVersion: RawTokenSyntax? {
20066+
layoutView.children[9].map(RawTokenSyntax.init(raw:))
20067+
}
20068+
20069+
public var unexpectedAfterPatchVersion: RawUnexpectedNodesSyntax? {
20070+
layoutView.children[10].map(RawUnexpectedNodesSyntax.init(raw:))
20071+
}
2004820072
}
2004920073

2005020074
@_spi(RawSyntax)

Sources/SwiftSyntax/generated/raw/RawSyntaxValidation.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2302,14 +2302,18 @@ func validateLayout(layout: RawSyntaxBuffer, as kind: SyntaxKind) {
23022302
assertNoError(kind, 7, verify(layout[7], as: RawPatternBindingListSyntax.self))
23032303
assertNoError(kind, 8, verify(layout[8], as: RawUnexpectedNodesSyntax?.self))
23042304
case .versionTuple:
2305-
assert(layout.count == 7)
2305+
assert(layout.count == 11)
23062306
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))
23072307
assertNoError(kind, 1, verify(layout[1], as: RawTokenSyntax.self))
23082308
assertNoError(kind, 2, verify(layout[2], as: RawUnexpectedNodesSyntax?.self))
23092309
assertNoError(kind, 3, verify(layout[3], as: RawTokenSyntax?.self))
23102310
assertNoError(kind, 4, verify(layout[4], as: RawUnexpectedNodesSyntax?.self))
23112311
assertNoError(kind, 5, verify(layout[5], as: RawTokenSyntax?.self))
23122312
assertNoError(kind, 6, verify(layout[6], as: RawUnexpectedNodesSyntax?.self))
2313+
assertNoError(kind, 7, verify(layout[7], as: RawTokenSyntax?.self))
2314+
assertNoError(kind, 8, verify(layout[8], as: RawUnexpectedNodesSyntax?.self))
2315+
assertNoError(kind, 9, verify(layout[9], as: RawTokenSyntax?.self))
2316+
assertNoError(kind, 10, verify(layout[10], as: RawUnexpectedNodesSyntax?.self))
23132317
case .whereClause:
23142318
assert(layout.count == 5)
23152319
assertNoError(kind, 0, verify(layout[0], as: RawUnexpectedNodesSyntax?.self))

0 commit comments

Comments
 (0)