Skip to content

Commit 3255377

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 20d083d commit 3255377

File tree

3 files changed

+68
-57
lines changed

3 files changed

+68
-57
lines changed

Sources/SwiftSyntax/Syntax.swift

Lines changed: 2 additions & 2 deletions
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.

Sources/SwiftSyntax/SyntaxClassifier.swift

Lines changed: 1 addition & 1 deletion
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
}

Sources/SwiftSyntax/SyntaxData.swift

Lines changed: 65 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -179,71 +179,78 @@ struct AbsoluteRawSyntax {
179179
}
180180
}
181181

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

188-
init(_ value: Syntax) {
189-
self.value = value
196+
// For non-root nodes.
197+
struct Edge {
198+
var parent: SyntaxData
199+
var absoluteInfo: AbsoluteSyntaxInfo
200+
}
190201
}
191202

192-
// SyntaxBox should be transparent in all descriptions
203+
private let info: Info
204+
let raw: RawSyntax
193205

194-
/// A source-accurate description of this node.
195-
var description: String {
196-
return value.description
206+
private var rootInfo: Info.Root {
207+
switch info {
208+
case .root(let info): return info
209+
case .edge(let info): return info.parent.rootInfo
210+
}
197211
}
198212

199-
/// Returns a description used by dump.
200-
var debugDescription: String {
201-
return value.debugDescription
213+
private var edgeInfo: Info.Edge? {
214+
switch info {
215+
case .root(_): return nil
216+
case .edge(let info): return info
217+
}
202218
}
203219

204-
/// Prints the raw value of this node to the provided stream.
205-
/// - Parameter stream: The stream to which to print the raw tree.
206-
func write<Target>(to target: inout Target)
207-
where Target: TextOutputStream {
208-
return value.write(to: &target)
220+
private var rootArena: SyntaxArena {
221+
rootInfo.arena
209222
}
210-
}
211223

212-
/// SyntaxData is the underlying storage for each Syntax node.
213-
///
214-
/// SyntaxData is an implementation detail, and should not be exposed to clients
215-
/// of SwiftSyntax.
216-
struct SyntaxData {
217-
private enum ParentOrArena {
218-
// For non-root nodes.
219-
case parent(SyntaxBox)
220-
// For root node.
221-
case arena(SyntaxArena)
222-
}
223-
private let parentOrArena: ParentOrArena
224-
private var arena: SyntaxArena {
225-
switch parentOrArena {
226-
case .arena(let arena): return arena
227-
case .parent(let parentBox): return parentBox.value.data.arena
224+
private var root: SyntaxData {
225+
switch info {
226+
case .root(_): return self
227+
case .edge(let info): return info.parent.root
228228
}
229229
}
230-
var parent: Syntax? {
231-
switch parentOrArena {
232-
case .parent(let parentBox): return parentBox.value
233-
case .arena(_): return nil
234-
}
230+
231+
var parent: SyntaxData? {
232+
edgeInfo?.parent
235233
}
236-
let absoluteRaw: AbsoluteRawSyntax
237234

238-
var raw: RawSyntax { return absoluteRaw.raw }
235+
var absoluteInfo: AbsoluteSyntaxInfo {
236+
edgeInfo?.absoluteInfo ?? .forRoot(raw)
237+
}
239238

240-
var indexInParent: Int { return Int(absoluteRaw.info.indexInParent) }
239+
var absoluteRaw: AbsoluteRawSyntax {
240+
AbsoluteRawSyntax(raw: raw, info: absoluteInfo)
241+
}
241242

242-
var nodeId: SyntaxIdentifier { return absoluteRaw.info.nodeId }
243+
var indexInParent: Int {
244+
Int(absoluteInfo.indexInParent)
245+
}
246+
247+
var nodeId: SyntaxIdentifier {
248+
absoluteInfo.nodeId
249+
}
243250

244251
/// The position of the start of this node's leading trivia
245252
var position: AbsolutePosition {
246-
return absoluteRaw.position
253+
AbsolutePosition(utf8Offset: Int(absoluteInfo.offset))
247254
}
248255

249256
/// The position of the start of this node's content, skipping its trivia
@@ -258,26 +265,30 @@ struct SyntaxData {
258265

259266
/// The end position of this node, including its trivia.
260267
var endPosition: AbsolutePosition {
261-
return absoluteRaw.endPosition
268+
position + raw.totalLength
262269
}
263270

264271
/// "designated" memberwise initializer of `SyntaxData`.
265-
private init(_ absoluteRaw: AbsoluteRawSyntax, parentOrArena: ParentOrArena) {
266-
self.parentOrArena = parentOrArena
267-
self.absoluteRaw = absoluteRaw
272+
private init(_ raw: RawSyntax, info: Info) {
273+
self.raw = raw
274+
self.info = info
275+
}
276+
277+
init(_ raw: RawSyntax, parent: SyntaxData, absoluteInfo: AbsoluteSyntaxInfo) {
278+
self.init(raw, info: .edge(.init(parent: parent, absoluteInfo: absoluteInfo)))
268279
}
269280

270281
/// Creates a `SyntaxData` with the provided raw syntax and parent.
271282
/// - Parameters:
272283
/// - absoluteRaw: The underlying `AbsoluteRawSyntax` of this node.
273284
/// - parent: The parent of this node, or `nil` if this node is the root.
274285
init(_ absoluteRaw: AbsoluteRawSyntax, parent: Syntax) {
275-
self.init(absoluteRaw, parentOrArena: .parent(SyntaxBox(parent)))
286+
self.init(absoluteRaw.raw, parent: parent.data, absoluteInfo: absoluteRaw.info)
276287
}
277288

278289
/// Creates a `SyntaxData` for a root raw node.
279290
static func forRoot(_ raw: RawSyntax) -> SyntaxData {
280-
SyntaxData(.forRoot(raw), parentOrArena: .arena(raw.arena))
291+
SyntaxData(raw, info: .root(.init(arena: raw.arena)))
281292
}
282293

283294
/// Returns the child data at the provided index in this data's layout.
@@ -295,7 +306,7 @@ struct SyntaxData {
295306
var iter = RawSyntaxChildren(absoluteRaw).makeIterator()
296307
for _ in 0..<index { _ = iter.next() }
297308
let (raw, info) = iter.next()!
298-
return SyntaxData(AbsoluteRawSyntax(raw: raw!, info: info), parent: parent)
309+
return SyntaxData(raw!, parent: self, absoluteInfo: info)
299310
}
300311

301312
/// Creates a copy of `self` and recursively creates `SyntaxData` nodes up to
@@ -308,7 +319,7 @@ struct SyntaxData {
308319
// If we have a parent already, then ask our current parent to copy itself
309320
// recursively up to the root.
310321
if let parent = parent {
311-
let parentData = parent.data.replacingChild(newRaw, at: indexInParent)
322+
let parentData = parent.replacingChild(newRaw, at: indexInParent)
312323
let newParent = Syntax(parentData)
313324
return SyntaxData(absoluteRaw.replacingSelf(newRaw, newRootId: parentData.nodeId.rootId), parent: newParent)
314325
} else {

0 commit comments

Comments
 (0)