Skip to content

Commit 342a9d2

Browse files
authored
Bump allocated RawSyntax
* Introduce 'SyntaxArena' that manages the memory of RawSyntax * Refactor 'RawSyntax'. now it has - Unowned pointer to the 'SyntaxArena' - Tagged union of "token" or "layout" where all data are managed by the 'SyntaxArena' * Root 'SyntaxData' now owns 'SyntaxArena' of the root 'RawSyntax'
1 parent e5dc525 commit 342a9d2

21 files changed

+1964
-2433
lines changed

Sources/SwiftSyntax/CNodes.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ typealias CTokenData = swiftparse_token_data_t
2525
typealias CLayoutData = swiftparse_layout_data_t
2626
typealias CTriviaPiecePtr = UnsafePointer<CTriviaPiece>
2727
typealias CTriviaPiece = swiftparse_trivia_piece_t
28+
typealias CRange = swiftparse_range_t
2829

2930
/// Computes a hash value that describes the layout of all C nodes which are
3031
/// passed as opaque values between `SwiftSyntaxParser` and `SwiftSyntax`.
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
//===------------------- RawSyntax+CSwiftSyntax.swift ---------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
@_implementationOnly import _CSwiftSyntax
14+
15+
extension RawSyntax {
16+
static func createFromCSyntaxNode(
17+
_ p: CSyntaxNodePtr,
18+
in sourceBuffer: UnsafeBufferPointer<UInt8>,
19+
arena: SyntaxArena
20+
) -> RawSyntax {
21+
let cnode = p.pointee
22+
if cnode.kind == 0 {
23+
// Token.
24+
25+
func sliceSourceText(_ r: CRange) -> SyntaxText {
26+
let sourceText = SyntaxText(
27+
baseAddress: sourceBuffer.baseAddress, count: sourceBuffer.count)
28+
let range = Int(r.offset) ..< Int(r.offset + r.length)
29+
return SyntaxText(rebasing: sourceText[range])
30+
}
31+
32+
let tokenKind: RawTokenKind = RawTokenKind.fromRawValue(cnode.token_data.kind)
33+
/// Whole text of the token including leading/trailing trivia.
34+
let wholeText: SyntaxText = sliceSourceText(cnode.token_data.range)
35+
36+
// These numbers are being adjusted while materializing trivia.
37+
var tokenTextStart = 0
38+
var tokenTextEnd = wholeText.count
39+
40+
// Prepare trivia.
41+
let leadingTriviaInfo = UnsafeBufferPointer<swiftparse_trivia_piece_t>(
42+
start: cnode.token_data.leading_trivia, count: numericCast(cnode.token_data.leading_trivia_count))
43+
let trailingTriviaInfo = UnsafeBufferPointer<swiftparse_trivia_piece_t>(
44+
start: cnode.token_data.trailing_trivia, count: numericCast(cnode.token_data.trailing_trivia_count))
45+
46+
let pieceBuffer = arena.allocateRawTriviaPieceBuffer(
47+
count: leadingTriviaInfo.count + trailingTriviaInfo.count)
48+
let numLeadingTrivia = leadingTriviaInfo.count
49+
50+
// Materialize the leading trivia, and advance 'tokenTextStart' to point
51+
// the end of leading trivia.
52+
for i in 0..<numLeadingTrivia {
53+
let cPiece = leadingTriviaInfo[i]
54+
let pieceStart = tokenTextStart
55+
let pieceEnd = tokenTextStart + numericCast(cPiece.length)
56+
let pieceText = SyntaxText(rebasing: wholeText[pieceStart ..< pieceEnd])
57+
let piece = RawTriviaPiece.fromRawValue(kind: cPiece.kind, text: pieceText)
58+
pieceBuffer.baseAddress!.advanced(by: i).initialize(to: piece)
59+
tokenTextStart = pieceEnd
60+
}
61+
// Materialize the trailing trivia, and retreat 'tokenTextEnd' to point
62+
// point the start of trailing trivia.
63+
for i in (0..<trailingTriviaInfo.count).reversed() {
64+
let cPiece = trailingTriviaInfo[i]
65+
let pieceStart = tokenTextEnd - numericCast(cPiece.length)
66+
let pieceEnd = tokenTextEnd
67+
let pieceText = SyntaxText(rebasing: wholeText[pieceStart ..< pieceEnd])
68+
let piece = RawTriviaPiece.fromRawValue(kind: cPiece.kind, text: pieceText)
69+
pieceBuffer.baseAddress!.advanced(by: numLeadingTrivia + i).initialize(to: piece)
70+
tokenTextEnd = pieceStart
71+
}
72+
73+
// Slice the text
74+
let tokenText = SyntaxText(rebasing: wholeText[tokenTextStart ..< tokenTextEnd])
75+
76+
// Total length of the pieces must match the whole text.
77+
assert(tokenText.count + pieceBuffer.reduce(0, {$0 + $1.byteLength}) == wholeText.count)
78+
79+
return RawSyntax.materializedToken(
80+
kind: tokenKind, text: tokenText,
81+
triviaPieces: RawTriviaPieceBuffer(pieceBuffer),
82+
numLeadingTrivia: numericCast(numLeadingTrivia),
83+
byteLength: numericCast(wholeText.count),
84+
arena: arena)
85+
} else {
86+
// Layout.
87+
88+
let syntaxKind = SyntaxKind(rawValue: numericCast(cnode.kind))!
89+
90+
let count = Int(cnode.layout_data.nodes_count)
91+
if count == 0 {
92+
return makeEmptyLayout(kind: syntaxKind, arena: arena)
93+
}
94+
95+
// '!' because we know 'count' is not 0.
96+
let nodes: UnsafePointer<CClientNode?> = cnode.layout_data.nodes!
97+
return makeLayout(
98+
kind: syntaxKind,
99+
uninitializedCount: count,
100+
arena: arena
101+
) { buffer in
102+
var ptr = buffer.baseAddress!
103+
for i in 0 ..< count {
104+
let element: RawSyntax? = nodes[i].map {
105+
// 'CClinentNode' is a pointer to a 'RawSyntaxData'.
106+
return RawSyntax.fromOpaque(UnsafeRawPointer($0))
107+
}
108+
ptr.initialize(to: element)
109+
ptr += 1
110+
}
111+
}
112+
}
113+
}
114+
}

0 commit comments

Comments
 (0)