Sources/OrgCore/Syntax/SyntaxNode.swift
118 lines · 4010 bytes
1/// A view of a green node at an absolute offset, with a parent link. Created on demand.
2public final class SyntaxNode: Sendable {
3 public let green: GreenNode
4 public let offset: Int
5 public let parent: SyntaxNode?
6
7 init(green: GreenNode, offset: Int, parent: SyntaxNode?) {
8 self.green = green
9 self.offset = offset
10 self.parent = parent
11 }
12
13 public var kind: SyntaxKind { green.kind }
14 public var range: Range<Int> { offset..<(offset + green.length) }
15 public var text: String { green.text }
16
17 public var children: [SyntaxNode] {
18 var result: [SyntaxNode] = []
19 var at = offset
20 for child in green.children {
21 if case .node(let node) = child {
22 result.append(SyntaxNode(green: node, offset: at, parent: self))
23 }
24 at += child.length
25 }
26 return result
27 }
28
29 public var tokens: [SyntaxToken] {
30 var result: [SyntaxToken] = []
31 var at = offset
32 for child in green.children {
33 if case .token(let token) = child {
34 result.append(SyntaxToken(kind: token.kind, text: token.text, range: at..<(at + token.length)))
35 }
36 at += child.length
37 }
38 return result
39 }
40
41 /// Child nodes overlapping `range`. Only those are created, so a section with thousands of
42 /// children costs little when the range is small.
43 public func children(overlapping range: Range<Int>) -> [SyntaxNode] {
44 var result: [SyntaxNode] = []
45 var at = offset
46 for child in green.children {
47 let childRange = at..<(at + child.length)
48 if childRange.lowerBound >= range.upperBound, !range.isEmpty { break }
49 if case .node(let node) = child, childRange.overlaps(range) {
50 result.append(SyntaxNode(green: node, offset: at, parent: self))
51 }
52 at = childRange.upperBound
53 }
54 return result
55 }
56
57 /// The child node whose range contains `position`.
58 public func child(containing position: Int) -> SyntaxNode? {
59 var at = offset
60 for child in green.children {
61 let end = at + child.length
62 if position < end {
63 if case .node(let node) = child, position >= at { return SyntaxNode(green: node, offset: at, parent: self) }
64 return nil
65 }
66 at = end
67 }
68 return nil
69 }
70
71 /// The first child node of `kind`.
72 public func firstChild(_ kind: SyntaxKind) -> SyntaxNode? {
73 var at = offset
74 for child in green.children {
75 if case .node(let node) = child, node.kind == kind { return SyntaxNode(green: node, offset: at, parent: self) }
76 at += child.length
77 }
78 return nil
79 }
80
81 public enum Element {
82 case node(SyntaxNode)
83 case token(SyntaxToken)
84 }
85
86 /// Child nodes and tokens in document order.
87 public var elements: [Element] {
88 var result: [Element] = []
89 var at = offset
90 for child in green.children {
91 switch child {
92 case .node(let node): result.append(.node(SyntaxNode(green: node, offset: at, parent: self)))
93 case .token(let token): result.append(.token(SyntaxToken(kind: token.kind, text: token.text, range: at..<(at + child.length))))
94 }
95 at += child.length
96 }
97 return result
98 }
99
100 /// This node and every node below it, in document order.
101 public func descendants() -> [SyntaxNode] {
102 [self] + children.flatMap { $0.descendants() }
103 }
104}
105
106public struct SyntaxToken: Sendable, Equatable {
107 public let kind: SyntaxKind
108 public let text: String
109 public let range: Range<Int>
110}
111
112public struct OrgTree: Sendable {
113 public let green: GreenNode
114 public let settings: OrgSettings
115
116 public var root: SyntaxNode { SyntaxNode(green: green, offset: 0, parent: nil) }
117 public var text: String { green.text }
118}