|
11 | 11 | //===----------------------------------------------------------------------===//
|
12 | 12 |
|
13 | 13 | public class SyntaxArena {
|
14 |
| - |
15 |
| - @_spi(RawSyntax) |
16 |
| - public typealias ParseTriviaFunction = (_ source: SyntaxText, _ position: TriviaPosition) -> [RawTriviaPiece] |
17 |
| - |
18 | 14 | /// Bump-pointer allocator for all "intern" methods.
|
19 |
| - private let allocator: BumpPtrAllocator |
20 |
| - /// Source file buffer the Syntax tree represents. |
21 |
| - private var sourceBuffer: UnsafeBufferPointer<UInt8> |
| 15 | + fileprivate let allocator: BumpPtrAllocator |
22 | 16 |
|
23 | 17 | /// If the syntax tree that’s allocated in this arena references nodes from
|
24 | 18 | /// other arenas, `childRefs` contains references to the arenas. Child arenas
|
25 | 19 | /// are retained in `addChild()` and are released in `deinit`.
|
26 | 20 | private var childRefs: Set<SyntaxArenaRef>
|
27 |
| - private var parseTriviaFunction: ParseTriviaFunction |
28 | 21 |
|
29 | 22 | #if DEBUG
|
30 | 23 | /// Whether or not this arena has been added to other arenas as a child.
|
31 | 24 | /// Used to make sure we don’t introduce retain cycles between arenas.
|
32 | 25 | private var hasParent: Bool
|
33 | 26 | #endif
|
34 | 27 |
|
35 |
| - @_spi(RawSyntax) |
36 |
| - public init(parseTriviaFunction: @escaping ParseTriviaFunction) { |
37 |
| - self.allocator = BumpPtrAllocator() |
| 28 | + public convenience init() { |
| 29 | + self.init(slabSize: 128) |
| 30 | + } |
| 31 | + |
| 32 | + fileprivate init(slabSize: Int) { |
| 33 | + self.allocator = BumpPtrAllocator(slabSize: slabSize) |
38 | 34 | self.childRefs = []
|
39 |
| - self.sourceBuffer = .init(start: nil, count: 0) |
40 |
| - self.parseTriviaFunction = parseTriviaFunction |
41 | 35 | #if DEBUG
|
42 | 36 | self.hasParent = false
|
43 | 37 | #endif
|
44 | 38 | }
|
45 | 39 |
|
46 |
| - public convenience init() { |
47 |
| - self.init(parseTriviaFunction: _defaultParseTriviaFunction(_:_:)) |
48 |
| - } |
49 |
| - |
50 | 40 | deinit {
|
51 | 41 | for child in childRefs {
|
52 | 42 | child.release()
|
53 | 43 | }
|
54 | 44 | }
|
55 | 45 |
|
56 |
| - /// Copies a source buffer in to the memory this arena manages, and returns |
57 |
| - /// the interned buffer. |
58 |
| - /// |
59 |
| - /// The interned buffer is guaranteed to be null-terminated. |
60 |
| - /// `contains(address _:)` is faster if the address is inside the memory |
61 |
| - /// range this function returned. |
62 |
| - public func internSourceBuffer(_ buffer: UnsafeBufferPointer<UInt8>) -> UnsafeBufferPointer<UInt8> { |
63 |
| - let allocated = allocator.allocate( |
64 |
| - UInt8.self, count: buffer.count + /* for NULL */1) |
65 |
| - precondition(sourceBuffer.baseAddress == nil, "SourceBuffer should only be set once.") |
66 |
| - _ = allocated.initialize(from: buffer) |
67 |
| - |
68 |
| - // NULL terminate. |
69 |
| - allocated.baseAddress!.advanced(by: buffer.count).initialize(to: 0) |
70 |
| - |
71 |
| - sourceBuffer = UnsafeBufferPointer(start: allocated.baseAddress!, count: buffer.count) |
72 |
| - return sourceBuffer |
73 |
| - } |
74 |
| - |
75 |
| - /// Checks if the given memory address is inside the memory range returned |
76 |
| - /// from `internSourceBuffer(_:)` method. |
77 |
| - func sourceBufferContains(_ address: UnsafePointer<UInt8>) -> Bool { |
78 |
| - guard let sourceStart = sourceBuffer.baseAddress else { return false } |
79 |
| - return sourceStart <= address && address < sourceStart.advanced(by: sourceBuffer.count) |
80 |
| - } |
81 |
| - |
82 | 46 | /// Allocates a buffer of `RawSyntax?` with the given count, then returns the
|
83 | 47 | /// uninitlialized memory range as a `UnsafeMutableBufferPointer<RawSyntax?>`.
|
84 | 48 | func allocateRawSyntaxBuffer(count: Int) -> UnsafeMutableBufferPointer<RawSyntax?> {
|
@@ -173,10 +137,63 @@ public class SyntaxArena {
|
173 | 137 | @_spi(RawSyntax)
|
174 | 138 | public func contains(text: SyntaxText) -> Bool {
|
175 | 139 | return (text.isEmpty ||
|
176 |
| - sourceBufferContains(text.baseAddress!) || |
177 | 140 | allocator.contains(address: text.baseAddress!))
|
178 | 141 | }
|
| 142 | +} |
| 143 | + |
| 144 | +/// SyntaxArena for parsing. |
| 145 | +public class ParsingSyntaxArena: SyntaxArena { |
| 146 | + @_spi(RawSyntax) |
| 147 | + public typealias ParseTriviaFunction = (_ source: SyntaxText, _ position: TriviaPosition) -> [RawTriviaPiece] |
| 148 | + |
| 149 | + /// Source file buffer the Syntax tree represents. |
| 150 | + private var sourceBuffer: UnsafeBufferPointer<UInt8> |
| 151 | + |
| 152 | + /// Function to parse trivia. |
| 153 | + private var parseTriviaFunction: ParseTriviaFunction |
| 154 | + |
| 155 | + @_spi(RawSyntax) |
| 156 | + public init(parseTriviaFunction: @escaping ParseTriviaFunction) { |
| 157 | + self.sourceBuffer = .init(start: nil, count: 0) |
| 158 | + self.parseTriviaFunction = parseTriviaFunction |
| 159 | + super.init(slabSize: 4096) |
| 160 | + } |
179 | 161 |
|
| 162 | + /// Copies a source buffer in to the memory this arena manages, and returns |
| 163 | + /// the interned buffer. |
| 164 | + /// |
| 165 | + /// The interned buffer is guaranteed to be null-terminated. |
| 166 | + /// `contains(address _:)` is faster if the address is inside the memory |
| 167 | + /// range this function returned. |
| 168 | + public func internSourceBuffer(_ buffer: UnsafeBufferPointer<UInt8>) -> UnsafeBufferPointer<UInt8> { |
| 169 | + let allocated = allocator.allocate( |
| 170 | + UInt8.self, count: buffer.count + /* for NULL */1) |
| 171 | + precondition(sourceBuffer.baseAddress == nil, "SourceBuffer should only be set once.") |
| 172 | + _ = allocated.initialize(from: buffer) |
| 173 | + |
| 174 | + // NULL terminate. |
| 175 | + allocated.baseAddress!.advanced(by: buffer.count).initialize(to: 0) |
| 176 | + |
| 177 | + sourceBuffer = UnsafeBufferPointer(start: allocated.baseAddress!, count: buffer.count) |
| 178 | + return sourceBuffer |
| 179 | + } |
| 180 | + |
| 181 | + @_spi(RawSyntax) |
| 182 | + public override func contains(text: SyntaxText) -> Bool { |
| 183 | + if let addr = text.baseAddress, self.sourceBufferContains(addr) { |
| 184 | + return true |
| 185 | + } |
| 186 | + return super.contains(text: text) |
| 187 | + } |
| 188 | + |
| 189 | + /// Checks if the given memory address is inside the memory range returned |
| 190 | + /// from `internSourceBuffer(_:)` method. |
| 191 | + func sourceBufferContains(_ address: UnsafePointer<UInt8>) -> Bool { |
| 192 | + guard let sourceStart = sourceBuffer.baseAddress else { return false } |
| 193 | + return sourceStart <= address && address < sourceStart.advanced(by: sourceBuffer.count) |
| 194 | + } |
| 195 | + |
| 196 | + /// Parse `source` into a list of `RawTriviaPiece` using `parseTriviaFunction`. |
180 | 197 | @_spi(RawSyntax)
|
181 | 198 | public func parseTrivia(source: SyntaxText, position: TriviaPosition) -> [RawTriviaPiece] {
|
182 | 199 | return self.parseTriviaFunction(source, position)
|
@@ -217,7 +234,3 @@ struct SyntaxArenaRef: Hashable {
|
217 | 234 | return lhs._value.toOpaque() == rhs._value.toOpaque()
|
218 | 235 | }
|
219 | 236 | }
|
220 |
| - |
221 |
| -private func _defaultParseTriviaFunction(_ source: SyntaxText, _ position: TriviaPosition) -> [RawTriviaPiece] { |
222 |
| - preconditionFailure("Trivia parsing not supported") |
223 |
| -} |
|
0 commit comments