10
10
//
11
11
//===----------------------------------------------------------------------===//
12
12
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
-
49
13
/// Provides a stable and unique identity for ``Syntax`` nodes.
50
14
///
51
15
/// Note that two nodes might have the same contents even if their IDs are
@@ -57,7 +21,53 @@ public struct SyntaxIndexInTree: Comparable, Hashable, Sendable {
57
21
/// different syntax tree. Modifying any node in the syntax tree a node is
58
22
/// contained in generates a copy of that tree and thus changes the IDs of all
59
23
/// 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
+
61
71
/// Unique value for the root node.
62
72
///
63
73
/// Multiple trees may have the same 'rootId' if their root RawSyntax is the
@@ -67,23 +77,65 @@ public struct SyntaxIdentifier: Hashable, Sendable {
67
77
let rootId : UInt
68
78
69
79
/// Unique value for a node within its own tree.
70
- @_spi ( RawSyntax)
71
80
public let indexInTree : SyntaxIndexInTree
72
81
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
+
73
87
func advancedBySibling( _ raw: RawSyntax ? ) -> SyntaxIdentifier {
74
88
let newIndexInTree = indexInTree. advancedBy ( raw)
75
- return . init ( rootId: self . rootId, indexInTree: newIndexInTree)
89
+ return SyntaxIdentifier ( rootId: self . rootId, indexInTree: newIndexInTree)
76
90
}
77
91
78
92
func advancedToFirstChild( ) -> SyntaxIdentifier {
79
93
let newIndexInTree = self . indexInTree. advancedToFirstChild ( )
80
- return . init ( rootId: self . rootId, indexInTree: newIndexInTree)
94
+ return SyntaxIdentifier ( rootId: self . rootId, indexInTree: newIndexInTree)
81
95
}
82
96
83
97
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 )
87
101
)
88
102
}
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
+ }
89
141
}
0 commit comments