Skip to content

Commit 4483276

Browse files
authored
Merge pull request #18276 from ahoppen/03-rawsyntax-struct
[libSyntax] Make RawSyntax a struct
2 parents b50294a + 478518f commit 4483276

File tree

7 files changed

+124
-108
lines changed

7 files changed

+124
-108
lines changed

tools/SwiftSyntax/RawSyntax.swift

Lines changed: 74 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ extension CodingUserInfoKey {
2929
struct SyntaxNodeId: Hashable, Codable {
3030
private let rawValue: UInt
3131

32+
// Start creating fresh node IDs for user generated nodes on in the upper
33+
// half of the UInt value range so that they don't easily collide with node
34+
// ids generated by the C++ side of libSyntax
35+
private static var highestUsedId: UInt = UInt.max / 2
36+
37+
/// Generates a syntax node ID that has not been used yet
38+
fileprivate static func generateFreshId() -> SyntaxNodeId {
39+
return SyntaxNodeId(rawValue: highestUsedId + 1)
40+
}
41+
3242
fileprivate init(rawValue: UInt) {
3343
self.rawValue = rawValue
3444
}
@@ -43,53 +53,57 @@ struct SyntaxNodeId: Hashable, Codable {
4353
}
4454
}
4555

56+
/// The data that is specific to a tree or token node
57+
fileprivate indirect enum RawSyntaxData {
58+
/// A tree node with a kind and an array of children
59+
case node(kind: SyntaxKind, layout: [RawSyntax?])
60+
/// A token with a token kind, leading trivia, and trailing trivia
61+
case token(kind: TokenKind, leadingTrivia: Trivia, trailingTrivia: Trivia)
62+
}
63+
4664
/// Represents the raw tree structure underlying the syntax tree. These nodes
4765
/// have no notion of identity and only provide structure to the tree. They
4866
/// are immutable and can be freely shared between syntax nodes.
49-
indirect enum RawSyntax: Codable {
50-
/// A tree node with a kind, an array of children, and a source presence.
51-
case node(SyntaxKind, [RawSyntax?], SourcePresence, SyntaxNodeId?)
67+
struct RawSyntax: Codable {
68+
fileprivate let data: RawSyntaxData
69+
let presence: SourcePresence
70+
let id: SyntaxNodeId
71+
72+
init(kind: SyntaxKind, layout: [RawSyntax?], presence: SourcePresence,
73+
id: SyntaxNodeId? = nil) {
74+
self.data = .node(kind: kind, layout: layout)
75+
self.presence = presence
76+
self.id = id ?? SyntaxNodeId.generateFreshId()
77+
}
5278

53-
/// A token with a token kind, leading trivia, trailing trivia, and a source
54-
/// presence.
55-
case token(TokenKind, Trivia, Trivia, SourcePresence, SyntaxNodeId?)
79+
init(kind: TokenKind, leadingTrivia: Trivia, trailingTrivia: Trivia,
80+
presence: SourcePresence, id: SyntaxNodeId? = nil) {
81+
self.data = .token(kind: kind, leadingTrivia: leadingTrivia,
82+
trailingTrivia: trailingTrivia)
83+
self.presence = presence
84+
self.id = id ?? SyntaxNodeId.generateFreshId()
85+
}
5686

5787
/// The syntax kind of this raw syntax.
5888
var kind: SyntaxKind {
59-
switch self {
60-
case .node(let kind, _, _, _): return kind
61-
case .token(_, _, _, _, _): return .token
89+
switch data {
90+
case .node(let kind, _): return kind
91+
case .token(_, _, _): return .token
6292
}
6393
}
6494

6595
var tokenKind: TokenKind? {
66-
switch self {
67-
case .node(_, _, _, _): return nil
68-
case .token(let kind, _, _, _, _): return kind
96+
switch data {
97+
case .node(_, _): return nil
98+
case .token(let kind, _, _): return kind
6999
}
70100
}
71101

72102
/// The layout of the children of this Raw syntax node.
73103
var layout: [RawSyntax?] {
74-
switch self {
75-
case .node(_, let layout, _, _): return layout
76-
case .token(_, _, _, _, _): return []
77-
}
78-
}
79-
80-
/// The source presence of this node.
81-
var presence: SourcePresence {
82-
switch self {
83-
case .node(_, _, let presence, _): return presence
84-
case .token(_, _, _, let presence, _): return presence
85-
}
86-
}
87-
88-
/// The ID of this node
89-
var id: SyntaxNodeId? {
90-
switch self {
91-
case .node(_, _, _, let id): return id
92-
case .token(_, _, _, _, let id): return id
104+
switch data {
105+
case .node(_, let layout): return layout
106+
case .token(_, _, _): return []
93107
}
94108
}
95109

@@ -152,12 +166,13 @@ indirect enum RawSyntax: Codable {
152166
let presence = try container.decode(SourcePresence.self, forKey: .presence)
153167
if let kind = try container.decodeIfPresent(SyntaxKind.self, forKey: .kind) {
154168
let layout = try container.decode([RawSyntax?].self, forKey: .layout)
155-
self = .node(kind, layout, presence, id)
169+
self.init(kind: kind, layout: layout, presence: presence, id: id)
156170
} else {
157171
let kind = try container.decode(TokenKind.self, forKey: .tokenKind)
158172
let leadingTrivia = try container.decode(Trivia.self, forKey: .leadingTrivia)
159173
let trailingTrivia = try container.decode(Trivia.self, forKey: .trailingTrivia)
160-
self = .token(kind, leadingTrivia, trailingTrivia, presence, id)
174+
self.init(kind: kind, leadingTrivia: leadingTrivia,
175+
trailingTrivia: trailingTrivia, presence: presence, id: id)
161176
}
162177
if let callback = decoder.userInfo[.rawSyntaxDecodedCallback] as?
163178
(RawSyntax) -> Void {
@@ -168,23 +183,18 @@ indirect enum RawSyntax: Codable {
168183
/// Encodes the RawSyntax to the provided Foundation Encoder.
169184
func encode(to encoder: Encoder) throws {
170185
var container = encoder.container(keyedBy: CodingKeys.self)
171-
switch self {
172-
case let .node(kind, layout, presence, id):
173-
if let id = id {
174-
try container.encode(id, forKey: .id)
175-
}
186+
switch self.data {
187+
case let .node(kind, layout):
188+
try container.encode(id, forKey: .id)
176189
try container.encode(kind, forKey: .kind)
177190
try container.encode(layout, forKey: .layout)
178-
try container.encode(presence, forKey: .presence)
179-
case let .token(kind, leadingTrivia, trailingTrivia, presence, id):
180-
if let id = id {
181-
try container.encode(id, forKey: .id)
182-
}
191+
case let .token(kind, leadingTrivia, trailingTrivia):
192+
try container.encode(id, forKey: .id)
183193
try container.encode(kind, forKey: .tokenKind)
184194
try container.encode(leadingTrivia, forKey: .leadingTrivia)
185195
try container.encode(trailingTrivia, forKey: .trailingTrivia)
186-
try container.encode(presence, forKey: .presence)
187196
}
197+
try container.encode(presence, forKey: .presence)
188198
}
189199

190200
/// Creates a RawSyntax node that's marked missing in the source with the
@@ -195,7 +205,7 @@ indirect enum RawSyntax: Codable {
195205
/// - Returns: A new RawSyntax `.node` with the provided kind and layout, with
196206
/// `.missing` source presence.
197207
static func missing(_ kind: SyntaxKind) -> RawSyntax {
198-
return .node(kind, [], .missing, nil)
208+
return RawSyntax(kind: kind, layout: [], presence: .missing)
199209
}
200210

201211
/// Creates a RawSyntax token that's marked missing in the source with the
@@ -204,7 +214,7 @@ indirect enum RawSyntax: Codable {
204214
/// - Returns: A new RawSyntax `.token` with the provided kind, no
205215
/// leading/trailing trivia, and `.missing` source presence.
206216
static func missingToken(_ kind: TokenKind) -> RawSyntax {
207-
return .token(kind, [], [], .missing, nil)
217+
return RawSyntax(kind: kind, leadingTrivia: [], trailingTrivia: [], presence: .missing)
208218
}
209219

210220
/// Returns a new RawSyntax node with the provided layout instead of the
@@ -213,10 +223,10 @@ indirect enum RawSyntax: Codable {
213223
/// is returned.
214224
/// - Parameter newLayout: The children of the new node you're creating.
215225
func replacingLayout(_ newLayout: [RawSyntax?]) -> RawSyntax {
216-
switch self {
217-
case let .node(kind, _, presence, _):
218-
return .node(kind, newLayout, presence, nil)
219-
case .token(_, _, _, _, _): return self
226+
switch data {
227+
case let .node(kind, _):
228+
return RawSyntax(kind: kind, layout: newLayout, presence: presence)
229+
case .token(_, _, _): return self
220230
}
221231
}
222232

@@ -259,14 +269,14 @@ extension RawSyntax: TextOutputStreamable {
259269
/// - Parameter stream: The stream on which to output this node.
260270
func write<Target>(to target: inout Target)
261271
where Target: TextOutputStream {
262-
switch self {
263-
case .node(_, let layout, _, _):
272+
switch data {
273+
case .node(_, let layout):
264274
for child in layout {
265275
guard let child = child else { continue }
266276
child.write(to: &target)
267277
}
268-
case let .token(kind, leadingTrivia, trailingTrivia, presence, _):
269-
guard case .present = presence else { return }
278+
case let .token(kind, leadingTrivia, trailingTrivia):
279+
guard isPresent else { return }
270280
for piece in leadingTrivia {
271281
piece.write(to: &target)
272282
}
@@ -280,14 +290,14 @@ extension RawSyntax: TextOutputStreamable {
280290

281291
extension RawSyntax {
282292
func accumulateAbsolutePosition(_ pos: AbsolutePosition) {
283-
switch self {
284-
case .node(_, let layout, _, _):
293+
switch data {
294+
case .node(_, let layout):
285295
for child in layout {
286296
guard let child = child else { continue }
287297
child.accumulateAbsolutePosition(pos)
288298
}
289-
case let .token(kind, leadingTrivia, trailingTrivia, presence, _):
290-
guard case .present = presence else { return }
299+
case let .token(kind, leadingTrivia, trailingTrivia):
300+
guard isPresent else { return }
291301
for piece in leadingTrivia {
292302
piece.accumulateAbsolutePosition(pos)
293303
}
@@ -299,31 +309,29 @@ extension RawSyntax {
299309
}
300310

301311
var leadingTrivia: Trivia? {
302-
switch self {
303-
case .node(_, let layout, _, _):
312+
switch data {
313+
case .node(_, let layout):
304314
for child in layout {
305315
guard let child = child else { continue }
306316
guard let result = child.leadingTrivia else { continue }
307317
return result
308318
}
309319
return nil
310-
case let .token(_, leadingTrivia, _, presence, _):
311-
guard case .present = presence else { return nil }
320+
case let .token(_, leadingTrivia, _):
312321
return leadingTrivia
313322
}
314323
}
315324

316325
var trailingTrivia: Trivia? {
317-
switch self {
318-
case .node(_, let layout, _, _):
326+
switch data {
327+
case .node(_, let layout):
319328
for child in layout.reversed() {
320329
guard let child = child else { continue }
321330
guard let result = child.trailingTrivia else { continue }
322331
return result
323332
}
324333
return nil
325-
case let .token(_, _, trailingTrivia, presence, _):
326-
guard case .present = presence else { return nil }
334+
case let .token(_, _, trailingTrivia):
327335
return trailingTrivia
328336
}
329337
}

tools/SwiftSyntax/SwiftSyntax.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,7 @@ public final class SyntaxTreeDeserializer {
7878
}
7979

8080
private func addToLookupTable(_ node: RawSyntax) {
81-
guard let id = node.id else {
82-
return
83-
}
84-
nodeLookupTable[id] = node
81+
nodeLookupTable[node.id] = node
8582
}
8683
}
8784

tools/SwiftSyntax/Syntax.swift

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -283,36 +283,40 @@ public struct TokenSyntax: _SyntaxBase, Hashable {
283283
/// Returns a new TokenSyntax with its kind replaced
284284
/// by the provided token kind.
285285
public func withKind(_ tokenKind: TokenKind) -> TokenSyntax {
286-
guard case let .token(_, leadingTrivia, trailingTrivia, presence, _) = raw else {
286+
guard raw.kind == .token else {
287287
fatalError("TokenSyntax must have token as its raw")
288288
}
289-
let (root, newData) = data.replacingSelf(.token(tokenKind, leadingTrivia,
290-
trailingTrivia, presence,
291-
nil))
289+
let newRaw = RawSyntax(kind: tokenKind, leadingTrivia: raw.leadingTrivia!,
290+
trailingTrivia: raw.trailingTrivia!,
291+
presence: raw.presence)
292+
let (root, newData) = data.replacingSelf(newRaw)
292293
return TokenSyntax(root: root, data: newData)
293294
}
294295

295296
/// Returns a new TokenSyntax with its leading trivia replaced
296297
/// by the provided trivia.
297298
public func withLeadingTrivia(_ leadingTrivia: Trivia) -> TokenSyntax {
298-
guard case let .token(kind, _, trailingTrivia, presence, _) = raw else {
299+
guard raw.kind == .token else {
299300
fatalError("TokenSyntax must have token as its raw")
300301
}
301-
let (root, newData) = data.replacingSelf(.token(kind, leadingTrivia,
302-
trailingTrivia, presence,
303-
nil))
302+
let newRaw = RawSyntax(kind: raw.tokenKind!, leadingTrivia: leadingTrivia,
303+
trailingTrivia: raw.trailingTrivia!,
304+
presence: raw.presence)
305+
let (root, newData) = data.replacingSelf(newRaw)
304306
return TokenSyntax(root: root, data: newData)
305307
}
306308

307309
/// Returns a new TokenSyntax with its trailing trivia replaced
308310
/// by the provided trivia.
309311
public func withTrailingTrivia(_ trailingTrivia: Trivia) -> TokenSyntax {
310-
guard case let .token(kind, leadingTrivia, _, presence, _) = raw else {
312+
guard raw.kind == .token else {
311313
fatalError("TokenSyntax must have token as its raw")
312314
}
313-
let (root, newData) = data.replacingSelf(.token(kind, leadingTrivia,
314-
trailingTrivia, presence,
315-
nil))
315+
let newRaw = RawSyntax(kind: raw.tokenKind!,
316+
leadingTrivia: raw.leadingTrivia!,
317+
trailingTrivia: trailingTrivia,
318+
presence: raw.presence)
319+
let (root, newData) = data.replacingSelf(newRaw)
316320
return TokenSyntax(root: root, data: newData)
317321
}
318322

@@ -333,26 +337,26 @@ public struct TokenSyntax: _SyntaxBase, Hashable {
333337

334338
/// The leading trivia (spaces, newlines, etc.) associated with this token.
335339
public var leadingTrivia: Trivia {
336-
guard case .token(_, let leadingTrivia, _, _, _) = raw else {
340+
guard raw.kind == .token else {
337341
fatalError("TokenSyntax must have token as its raw")
338342
}
339-
return leadingTrivia
343+
return raw.leadingTrivia!
340344
}
341345

342346
/// The trailing trivia (spaces, newlines, etc.) associated with this token.
343347
public var trailingTrivia: Trivia {
344-
guard case .token(_, _, let trailingTrivia, _, _) = raw else {
348+
guard raw.kind == .token else {
345349
fatalError("TokenSyntax must have token as its raw")
346350
}
347-
return trailingTrivia
351+
return raw.trailingTrivia!
348352
}
349353

350354
/// The kind of token this node represents.
351355
public var tokenKind: TokenKind {
352-
guard case .token(let kind, _, _, _, _) = raw else {
356+
guard raw.kind == .token else {
353357
fatalError("TokenSyntax must have token as its raw")
354358
}
355-
return kind
359+
return raw.tokenKind!
356360
}
357361

358362
public static func ==(lhs: TokenSyntax, rhs: TokenSyntax) -> Bool {

tools/SwiftSyntax/SyntaxBuilders.swift.gyb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ public struct ${Builder} {
4646
if let list = layout[idx] {
4747
layout[idx] = list.appending(elt.raw)
4848
} else {
49-
layout[idx] = RawSyntax.node(
50-
.${child.swift_syntax_kind}, [elt.raw], .present, nil)
49+
layout[idx] = RawSyntax(kind: SyntaxKind.${child.swift_syntax_kind},
50+
layout: [elt.raw],
51+
presence: SourcePresence.present)
5152
}
5253
}
5354
% else:
@@ -68,8 +69,8 @@ public struct ${Builder} {
6869
% end
6970
% end
7071

71-
return SyntaxData(raw: .node(.${node.swift_syntax_kind},
72-
layout, .present, nil))
72+
return SyntaxData(raw: RawSyntax(kind: .${node.swift_syntax_kind},
73+
layout: layout, presence: .present))
7374
}
7475
}
7576

0 commit comments

Comments
 (0)