Skip to content

Commit 53d91e8

Browse files
committed
Move AbsoluteSyntaxInfo to "edge" SyntaxData information
The root node doesn't need to hold its `AbsoluteSyntaxInfo` because it's always zero. Move this information to "edge" data so only non-root nodes hold the "absolute info". Introduce an "edge" info struct, and use it with `indirect` enum case instead of `SyntaxBox`. Previously the structure of `SyntaxData` was: * AbsoluteRawSyntax * RawSyntax * AbsoluteSyntaxInfo * Tagged union of * SyntaxArena * SyntaxBox * Parent SyntaxData Now: * RawSyntax node * Tagged union of: * SyntaxData.Info.Root * SyntaxArena * SyntaxData.Info.Edge (indirect case) * Parent SyntaxData * AbsoluteSyntaxInfo This reduces the size of `SyntaxData` to 2 words. Also `SyntaxData.parent` now returns `SyntaxData` instead of `Syntax`. `SyntaxData` should not rely on `Syntax` API at all.
1 parent c226bdc commit 53d91e8

File tree

3 files changed

+68
-57
lines changed

3 files changed

+68
-57
lines changed

Diff for: Sources/SwiftSyntax/Syntax.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public extension SyntaxProtocol {
143143

144144
/// The index of this node in a `SyntaxChildren` collection.
145145
var index: SyntaxChildrenIndex {
146-
return SyntaxChildrenIndex(self.data.absoluteRaw.info)
146+
return SyntaxChildrenIndex(self.data.absoluteInfo)
147147
}
148148

149149
/// Whether or not this node is a token one.
@@ -171,7 +171,7 @@ public extension SyntaxProtocol {
171171

172172
/// The parent of this syntax node, or `nil` if this node is the root.
173173
var parent: Syntax? {
174-
return data.parent
174+
return data.parent.map(Syntax.init(_:))
175175
}
176176

177177
/// The index of this node in the parent's children.

Diff for: Sources/SwiftSyntax/SyntaxClassifier.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ extension SyntaxData {
1818
guard let parent = curData.parent else { break }
1919
contextualClassif = SyntaxClassification.classify(parentKind: parent.raw.kind,
2020
indexInParent: curData.indexInParent, childKind: raw.kind)
21-
curData = parent.data
21+
curData = parent
2222
} while contextualClassif == nil
2323
return contextualClassif
2424
}

Diff for: Sources/SwiftSyntax/SyntaxData.swift

+65-54
Original file line numberDiff line numberDiff line change
@@ -184,71 +184,78 @@ struct AbsoluteRawSyntax {
184184
}
185185
}
186186

187-
/// Indirect wrapper for a `Syntax` node to avoid cyclic inclusion of the
188-
/// `Syntax` struct in `SyntaxData`
189-
class SyntaxBox: CustomStringConvertible,
190-
CustomDebugStringConvertible, TextOutputStreamable {
191-
let value: Syntax
187+
/// SyntaxData is the underlying storage for each Syntax node.
188+
///
189+
/// SyntaxData is an implementation detail, and should not be exposed to clients
190+
/// of SwiftSyntax.
191+
struct SyntaxData {
192+
private enum Info {
193+
case root(Root)
194+
indirect case nonRoot(NonRoot)
195+
196+
// For root node.
197+
struct Root {
198+
var arena: SyntaxArena
199+
}
192200

193-
init(_ value: Syntax) {
194-
self.value = value
201+
// For non-root nodes.
202+
struct NonRoot {
203+
var parent: SyntaxData
204+
var absoluteInfo: AbsoluteSyntaxInfo
205+
}
195206
}
196207

197-
// SyntaxBox should be transparent in all descriptions
208+
private let info: Info
209+
let raw: RawSyntax
198210

199-
/// A source-accurate description of this node.
200-
var description: String {
201-
return value.description
211+
private var rootInfo: Info.Root {
212+
switch info {
213+
case .root(let info): return info
214+
case .nonRoot(let info): return info.parent.rootInfo
215+
}
202216
}
203217

204-
/// Returns a description used by dump.
205-
var debugDescription: String {
206-
return value.debugDescription
218+
private var nonRootInfo: Info.NonRoot? {
219+
switch info {
220+
case .root(_): return nil
221+
case .nonRoot(let info): return info
222+
}
207223
}
208224

209-
/// Prints the raw value of this node to the provided stream.
210-
/// - Parameter stream: The stream to which to print the raw tree.
211-
func write<Target>(to target: inout Target)
212-
where Target: TextOutputStream {
213-
return value.write(to: &target)
225+
private var rootArena: SyntaxArena {
226+
rootInfo.arena
214227
}
215-
}
216228

217-
/// SyntaxData is the underlying storage for each Syntax node.
218-
///
219-
/// SyntaxData is an implementation detail, and should not be exposed to clients
220-
/// of SwiftSyntax.
221-
struct SyntaxData {
222-
private enum ParentOrArena {
223-
// For non-root nodes.
224-
case parent(SyntaxBox)
225-
// For root node.
226-
case arena(SyntaxArena)
227-
}
228-
private let parentOrArena: ParentOrArena
229-
private var arena: SyntaxArena {
230-
switch parentOrArena {
231-
case .arena(let arena): return arena
232-
case .parent(let parentBox): return parentBox.value.data.arena
229+
private var root: SyntaxData {
230+
switch info {
231+
case .root(_): return self
232+
case .nonRoot(let info): return info.parent.root
233233
}
234234
}
235-
var parent: Syntax? {
236-
switch parentOrArena {
237-
case .parent(let parentBox): return parentBox.value
238-
case .arena(_): return nil
239-
}
235+
236+
var parent: SyntaxData? {
237+
nonRootInfo?.parent
240238
}
241-
let absoluteRaw: AbsoluteRawSyntax
242239

243-
var raw: RawSyntax { return absoluteRaw.raw }
240+
var absoluteInfo: AbsoluteSyntaxInfo {
241+
nonRootInfo?.absoluteInfo ?? .forRoot(raw)
242+
}
244243

245-
var indexInParent: Int { return Int(absoluteRaw.info.indexInParent) }
244+
var absoluteRaw: AbsoluteRawSyntax {
245+
AbsoluteRawSyntax(raw: raw, info: absoluteInfo)
246+
}
246247

247-
var nodeId: SyntaxIdentifier { return absoluteRaw.info.nodeId }
248+
var indexInParent: Int {
249+
Int(absoluteInfo.indexInParent)
250+
}
251+
252+
var nodeId: SyntaxIdentifier {
253+
absoluteInfo.nodeId
254+
}
248255

249256
/// The position of the start of this node's leading trivia
250257
var position: AbsolutePosition {
251-
return absoluteRaw.position
258+
AbsolutePosition(utf8Offset: Int(absoluteInfo.offset))
252259
}
253260

254261
/// The position of the start of this node's content, skipping its trivia
@@ -263,26 +270,30 @@ struct SyntaxData {
263270

264271
/// The end position of this node, including its trivia.
265272
var endPosition: AbsolutePosition {
266-
return absoluteRaw.endPosition
273+
position + raw.totalLength
267274
}
268275

269276
/// "designated" memberwise initializer of `SyntaxData`.
270-
private init(_ absoluteRaw: AbsoluteRawSyntax, parentOrArena: ParentOrArena) {
271-
self.parentOrArena = parentOrArena
272-
self.absoluteRaw = absoluteRaw
277+
private init(_ raw: RawSyntax, info: Info) {
278+
self.raw = raw
279+
self.info = info
280+
}
281+
282+
init(_ raw: RawSyntax, parent: SyntaxData, absoluteInfo: AbsoluteSyntaxInfo) {
283+
self.init(raw, info: .nonRoot(.init(parent: parent, absoluteInfo: absoluteInfo)))
273284
}
274285

275286
/// Creates a `SyntaxData` with the provided raw syntax and parent.
276287
/// - Parameters:
277288
/// - absoluteRaw: The underlying `AbsoluteRawSyntax` of this node.
278289
/// - parent: The parent of this node, or `nil` if this node is the root.
279290
init(_ absoluteRaw: AbsoluteRawSyntax, parent: Syntax) {
280-
self.init(absoluteRaw, parentOrArena: .parent(SyntaxBox(parent)))
291+
self.init(absoluteRaw.raw, parent: parent.data, absoluteInfo: absoluteRaw.info)
281292
}
282293

283294
/// Creates a `SyntaxData` for a root raw node.
284295
static func forRoot(_ raw: RawSyntax) -> SyntaxData {
285-
SyntaxData(.forRoot(raw), parentOrArena: .arena(raw.arena))
296+
SyntaxData(raw, info: .root(.init(arena: raw.arena)))
286297
}
287298

288299
/// Returns the child data at the provided index in this data's layout.
@@ -300,7 +311,7 @@ struct SyntaxData {
300311
var iter = RawSyntaxChildren(absoluteRaw).makeIterator()
301312
for _ in 0..<index { _ = iter.next() }
302313
let (raw, info) = iter.next()!
303-
return SyntaxData(AbsoluteRawSyntax(raw: raw!, info: info), parent: parent)
314+
return SyntaxData(raw!, parent: self, absoluteInfo: info)
304315
}
305316

306317
/// Creates a copy of `self` and recursively creates `SyntaxData` nodes up to
@@ -313,7 +324,7 @@ struct SyntaxData {
313324
// If we have a parent already, then ask our current parent to copy itself
314325
// recursively up to the root.
315326
if let parent = parent {
316-
let parentData = parent.data.replacingChild(newRaw, at: indexInParent)
327+
let parentData = parent.replacingChild(newRaw, at: indexInParent)
317328
let newParent = Syntax(parentData)
318329
return SyntaxData(absoluteRaw.replacingSelf(newRaw, newRootId: parentData.nodeId.rootId), parent: newParent)
319330
} else {

0 commit comments

Comments
 (0)