1010//
1111//===----------------------------------------------------------------------===//
1212
13- /// Represents a unique value for a node within its own tree.
14- @_spi ( RawSyntax)
15- public struct SyntaxIndexInTree : Comparable , Hashable , Sendable {
16- let indexInTree : UInt32
17-
18- static let zero : SyntaxIndexInTree = SyntaxIndexInTree ( indexInTree: 0 )
19-
20- /// Assuming that this index points to the start of ``Raw``, so that it points
21- /// to the next sibling of ``Raw``.
22- func advancedBy( _ raw: RawSyntax ? ) -> SyntaxIndexInTree {
23- let newIndexInTree = self . indexInTree + UInt32( truncatingIfNeeded: raw? . totalNodes ?? 0 )
24- return . init( indexInTree: newIndexInTree)
25- }
26-
27- /// Assuming that this index points to the next sibling of ``Raw``, reverse it
28- /// so that it points to the start of ``Raw``.
29- func reversedBy( _ raw: RawSyntax ? ) -> SyntaxIndexInTree {
30- let newIndexInTree = self . indexInTree - UInt32( truncatingIfNeeded: raw? . totalNodes ?? 0 )
31- return . init( indexInTree: newIndexInTree)
32- }
33-
34- func advancedToFirstChild( ) -> SyntaxIndexInTree {
35- let newIndexInTree = self . indexInTree + 1
36- return . init( indexInTree: newIndexInTree)
37- }
38-
39- init ( indexInTree: UInt32 ) {
40- self . indexInTree = indexInTree
41- }
42-
43- /// Returns `true` if `lhs` occurs before `rhs` in the tree.
44- public static func < ( lhs: SyntaxIndexInTree , rhs: SyntaxIndexInTree ) -> Bool {
45- return lhs. indexInTree < rhs. indexInTree
46- }
47- }
48-
4913/// Provides a stable and unique identity for ``Syntax`` nodes.
5014///
5115/// Note that two nodes might have the same contents even if their IDs are
@@ -57,7 +21,53 @@ public struct SyntaxIndexInTree: Comparable, Hashable, Sendable {
5721/// different syntax tree. Modifying any node in the syntax tree a node is
5822/// contained in generates a copy of that tree and thus changes the IDs of all
5923/// nodes in the tree, not just the modified node's children.
60- public struct SyntaxIdentifier : Hashable , Sendable {
24+ public struct SyntaxIdentifier : Comparable , Hashable , Sendable {
25+ /// Represents a unique value for a node within its own tree.
26+ ///
27+ /// This is similar to ``SyntaxIdentifier`` but does not store the root ID of the tree.
28+ /// It can thus be transferred across trees that are structurally equivalent, for example two copies of the same tree
29+ /// that live in different processes.
30+ public struct SyntaxIndexInTree : Hashable , Sendable {
31+ /// When traversing the syntax tree using a depth-first traversal, the index at which the node will be visited.
32+ let indexInTree : UInt32
33+
34+ /// Assuming that this index points to the start of `raw`, advance it so that it points to the next sibling of
35+ /// `raw`.
36+ func advancedBy( _ raw: RawSyntax ? ) -> SyntaxIndexInTree {
37+ let newIndexInTree = self . indexInTree + UInt32( truncatingIfNeeded: raw? . totalNodes ?? 0 )
38+ return . init( indexInTree: newIndexInTree)
39+ }
40+
41+ /// Assuming that this index points to the next sibling of `raw`, reverse it so that it points to the start of
42+ /// `raw`.
43+ func reversedBy( _ raw: RawSyntax ? ) -> SyntaxIndexInTree {
44+ let newIndexInTree = self . indexInTree - UInt32( truncatingIfNeeded: raw? . totalNodes ?? 0 )
45+ return . init( indexInTree: newIndexInTree)
46+ }
47+
48+ func advancedToFirstChild( ) -> SyntaxIndexInTree {
49+ let newIndexInTree = self . indexInTree + 1
50+ return . init( indexInTree: newIndexInTree)
51+ }
52+
53+ init ( indexInTree: UInt32 ) {
54+ self . indexInTree = indexInTree
55+ }
56+
57+ /// Converts the ``SyntaxIdentifier/SyntaxIndexInTree`` to an opaque value that can be serialized.
58+ /// The opaque value can be restored to a ``SyntaxIdentifier/SyntaxIndexInTree`` using ``init(fromOpaque:)``.
59+ ///
60+ /// - Note: The contents of the opaque value are not specified and clients should not rely on them.
61+ public func toOpaque( ) -> UInt64 {
62+ return UInt64 ( indexInTree)
63+ }
64+
65+ /// Creates a ``SyntaxIdentifier/SyntaxIndexInTree`` from an opaque value obtained using ``toOpaque()``.
66+ public init ( fromOpaque opaque: UInt64 ) {
67+ self . indexInTree = UInt32 ( opaque)
68+ }
69+ }
70+
6171 /// Unique value for the root node.
6272 ///
6373 /// Multiple trees may have the same 'rootId' if their root RawSyntax is the
@@ -67,23 +77,65 @@ public struct SyntaxIdentifier: Hashable, Sendable {
6777 let rootId : UInt
6878
6979 /// Unique value for a node within its own tree.
70- @_spi ( RawSyntax)
7180 public let indexInTree : SyntaxIndexInTree
7281
82+ /// Returns the `UInt` that is used as the root ID for the given raw syntax node.
83+ private static func rootId( of raw: RawSyntax ) -> UInt {
84+ return UInt ( bitPattern: raw. pointer. unsafeRawPointer)
85+ }
86+
7387 func advancedBySibling( _ raw: RawSyntax ? ) -> SyntaxIdentifier {
7488 let newIndexInTree = indexInTree. advancedBy ( raw)
75- return . init ( rootId: self . rootId, indexInTree: newIndexInTree)
89+ return SyntaxIdentifier ( rootId: self . rootId, indexInTree: newIndexInTree)
7690 }
7791
7892 func advancedToFirstChild( ) -> SyntaxIdentifier {
7993 let newIndexInTree = self . indexInTree. advancedToFirstChild ( )
80- return . init ( rootId: self . rootId, indexInTree: newIndexInTree)
94+ return SyntaxIdentifier ( rootId: self . rootId, indexInTree: newIndexInTree)
8195 }
8296
8397 static func forRoot( _ raw: RawSyntax ) -> SyntaxIdentifier {
84- return . init (
85- rootId: UInt ( bitPattern : raw. pointer . unsafeRawPointer ) ,
86- indexInTree: . zero
98+ return SyntaxIdentifier (
99+ rootId: Self . rootId ( of : raw) ,
100+ indexInTree: SyntaxIndexInTree ( indexInTree : 0 )
87101 )
88102 }
103+
104+ /// Forms a ``SyntaxIdentifier`` from an ``SyntaxIdentifier/SyntaxIndexInTree`` inside a ``Syntax`` node that
105+ /// constitutes the tree's root.
106+ ///
107+ /// Returns `nil` if `root` is not the root of a syntax tree or if `indexInTree` points to a node that is not within
108+ /// the tree spanned up by `root`.
109+ ///
110+ /// - Warning: ``SyntaxIdentifier/SyntaxIndexInTree`` is not stable with regard to insertion or deletions of nodes
111+ /// into a syntax tree. There are only two scenarios where it is valid to share ``SyntaxIndexInTree`` between syntax
112+ /// trees with different nodes:
113+ /// (1) If two trees are guaranteed to be exactly the same eg. because they were parsed using the same version of
114+ /// `SwiftParser` from the same source code.
115+ /// (2) If a tree was mutated by only replacing tokens with other tokens. No nodes must have been inserted or
116+ /// removed during the process, including tokens that are marked as ``SourcePresence/missing``.
117+ public static func fromIndexInTree(
118+ _ indexInTree: SyntaxIndexInTree ,
119+ relativeToRoot root: some SyntaxProtocol
120+ ) -> SyntaxIdentifier ? {
121+ guard !root. hasParent else {
122+ return nil
123+ }
124+ guard indexInTree. indexInTree < SyntaxIndexInTree ( indexInTree: 0 ) . advancedBy ( root. raw) . indexInTree else {
125+ return nil
126+ }
127+
128+ return SyntaxIdentifier ( rootId: Self . rootId ( of: root. raw) , indexInTree: indexInTree)
129+ }
130+
131+ /// A ``SyntaxIdentifier`` compares less than another ``SyntaxIdentifier`` if the node at that identifier occurs first
132+ /// during a depth-first traversal of the tree. This implies that nodes with an earlier ``AbsolutePosition`` also
133+ /// have a lower ``SyntaxIdentifier``.
134+ public static func < ( lhs: SyntaxIdentifier , rhs: SyntaxIdentifier ) -> Bool {
135+ guard lhs. rootId == rhs. rootId else {
136+ // Nodes in different trees are not comparable.
137+ return false
138+ }
139+ return lhs. indexInTree. indexInTree < rhs. indexInTree. indexInTree
140+ }
89141}
0 commit comments