Skip to content

Move AbsoluteSyntaxInfo to "edge" SyntaxData information #659

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Sources/SwiftSyntax/Syntax.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public extension SyntaxProtocol {

/// The index of this node in a `SyntaxChildren` collection.
var index: SyntaxChildrenIndex {
return SyntaxChildrenIndex(self.data.absoluteRaw.info)
return SyntaxChildrenIndex(self.data.absoluteInfo)
}

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

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

/// The index of this node in the parent's children.
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftSyntax/SyntaxClassifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ extension SyntaxData {
guard let parent = curData.parent else { break }
contextualClassif = SyntaxClassification.classify(parentKind: parent.raw.kind,
indexInParent: curData.indexInParent, childKind: raw.kind)
curData = parent.data
curData = parent
} while contextualClassif == nil
return contextualClassif
}
Expand Down
119 changes: 65 additions & 54 deletions Sources/SwiftSyntax/SyntaxData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -184,71 +184,78 @@ struct AbsoluteRawSyntax {
}
}

/// Indirect wrapper for a `Syntax` node to avoid cyclic inclusion of the
/// `Syntax` struct in `SyntaxData`
class SyntaxBox: CustomStringConvertible,
CustomDebugStringConvertible, TextOutputStreamable {
let value: Syntax
/// SyntaxData is the underlying storage for each Syntax node.
///
/// SyntaxData is an implementation detail, and should not be exposed to clients
/// of SwiftSyntax.
struct SyntaxData {
private enum Info {
case root(Root)
indirect case nonRoot(NonRoot)

// For root node.
struct Root {
var arena: SyntaxArena
}

init(_ value: Syntax) {
self.value = value
// For non-root nodes.
struct NonRoot {
var parent: SyntaxData
var absoluteInfo: AbsoluteSyntaxInfo
}
}

// SyntaxBox should be transparent in all descriptions
private let info: Info
let raw: RawSyntax

/// A source-accurate description of this node.
var description: String {
return value.description
private var rootInfo: Info.Root {
switch info {
case .root(let info): return info
case .nonRoot(let info): return info.parent.rootInfo
}
}

/// Returns a description used by dump.
var debugDescription: String {
return value.debugDescription
private var nonRootInfo: Info.NonRoot? {
switch info {
case .root(_): return nil
case .nonRoot(let info): return info
}
}

/// Prints the raw value of this node to the provided stream.
/// - Parameter stream: The stream to which to print the raw tree.
func write<Target>(to target: inout Target)
where Target: TextOutputStream {
return value.write(to: &target)
private var rootArena: SyntaxArena {
rootInfo.arena
}
}

/// SyntaxData is the underlying storage for each Syntax node.
///
/// SyntaxData is an implementation detail, and should not be exposed to clients
/// of SwiftSyntax.
struct SyntaxData {
private enum ParentOrArena {
// For non-root nodes.
case parent(SyntaxBox)
// For root node.
case arena(SyntaxArena)
}
private let parentOrArena: ParentOrArena
private var arena: SyntaxArena {
switch parentOrArena {
case .arena(let arena): return arena
case .parent(let parentBox): return parentBox.value.data.arena
private var root: SyntaxData {
switch info {
case .root(_): return self
case .nonRoot(let info): return info.parent.root
}
}
var parent: Syntax? {
switch parentOrArena {
case .parent(let parentBox): return parentBox.value
case .arena(_): return nil
}

var parent: SyntaxData? {
nonRootInfo?.parent
}
let absoluteRaw: AbsoluteRawSyntax

var raw: RawSyntax { return absoluteRaw.raw }
var absoluteInfo: AbsoluteSyntaxInfo {
nonRootInfo?.absoluteInfo ?? .forRoot(raw)
}

var indexInParent: Int { return Int(absoluteRaw.info.indexInParent) }
var absoluteRaw: AbsoluteRawSyntax {
AbsoluteRawSyntax(raw: raw, info: absoluteInfo)
}

var nodeId: SyntaxIdentifier { return absoluteRaw.info.nodeId }
var indexInParent: Int {
Int(absoluteInfo.indexInParent)
}

var nodeId: SyntaxIdentifier {
absoluteInfo.nodeId
}

/// The position of the start of this node's leading trivia
var position: AbsolutePosition {
return absoluteRaw.position
AbsolutePosition(utf8Offset: Int(absoluteInfo.offset))
}

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

/// The end position of this node, including its trivia.
var endPosition: AbsolutePosition {
return absoluteRaw.endPosition
position + raw.totalLength
}

/// "designated" memberwise initializer of `SyntaxData`.
private init(_ absoluteRaw: AbsoluteRawSyntax, parentOrArena: ParentOrArena) {
self.parentOrArena = parentOrArena
self.absoluteRaw = absoluteRaw
private init(_ raw: RawSyntax, info: Info) {
self.raw = raw
self.info = info
}

init(_ raw: RawSyntax, parent: SyntaxData, absoluteInfo: AbsoluteSyntaxInfo) {
self.init(raw, info: .nonRoot(.init(parent: parent, absoluteInfo: absoluteInfo)))
}

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

/// Creates a `SyntaxData` for a root raw node.
static func forRoot(_ raw: RawSyntax) -> SyntaxData {
SyntaxData(.forRoot(raw), parentOrArena: .arena(raw.arena))
SyntaxData(raw, info: .root(.init(arena: raw.arena)))
}

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

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