Skip to content

Commit 714ab5e

Browse files
committed
Introduce a source accurate and structural view of a SwiftSyntax tree
`SyntaxTreeViewMode` allows two different views on a SwiftSyntax tree: 1. Either a purely `sourceAccurate` view, which skips over all missing children but traverses garbage syntax (once implemented). This mode is intended for clients that operate at the source code level, like swift-format 2. For clients that don’t care about 100% about source fidelity but would like to view the syntax tree for structural analysis with fixes from the parser applied, there’s the `fixedUp` view. This includes missing nodes (because the user probably meant to write these) and skips over garbage nodes (because the client will likely have a hard time reasoning about these nodes if the parser couldn’t make sense of them)
1 parent d9af173 commit 714ab5e

25 files changed

+248
-166
lines changed

Sources/SwiftSyntax/IncrementalParseTransition.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ public struct IncrementalParseLookup {
304304
if !edits.edits.isEmpty && edits.edits.first!.range.offset > nextSibling.endPosition.utf8Offset {
305305
return true
306306
}
307-
if let nextToken = nextSibling.raw.firstPresentToken {
307+
if let nextToken = nextSibling.raw.firstToken(syntaxTreeViewMode: .sourceAccurate) {
308308
nextLeafNodeLength = nextToken.totalLength - nextToken.trailingTriviaLength
309309
}
310310
}
@@ -350,6 +350,7 @@ fileprivate struct SyntaxCursor {
350350
var parents: [AbsoluteRawSyntax]
351351
var node: AbsoluteRawSyntax
352352
var finished: Bool
353+
let syntaxTreeViewMode = SyntaxTreeViewMode.sourceAccurate
353354

354355
init(root: AbsoluteRawSyntax) {
355356
self.node = root
@@ -368,7 +369,7 @@ fileprivate struct SyntaxCursor {
368369
var parents = ArraySlice(self.parents)
369370
var node = self.node
370371
while !parents.isEmpty {
371-
if let sibling = node.nextSibling(parent: parents.last!) {
372+
if let sibling = node.nextSibling(parent: parents.last!, syntaxTreeViewMode: syntaxTreeViewMode) {
372373
return sibling
373374
}
374375
node = parents.removeLast()
@@ -380,7 +381,7 @@ fileprivate struct SyntaxCursor {
380381
/// Moves to the first child of the current node.
381382
/// - Returns: False if the node has no children.
382383
mutating func advanceToFirstChild() -> Bool {
383-
guard let child = node.firstChild else { return false }
384+
guard let child = node.firstChild(syntaxTreeViewMode: syntaxTreeViewMode) else { return false }
384385
parents.append(node)
385386
node = child
386387
return true
@@ -391,7 +392,7 @@ fileprivate struct SyntaxCursor {
391392
/// - Returns: False if it run out of nodes to walk to.
392393
mutating func advanceToNextSibling() -> Bool {
393394
while !parents.isEmpty {
394-
if let sibling = node.nextSibling(parent: parents.last!) {
395+
if let sibling = node.nextSibling(parent: parents.last!, syntaxTreeViewMode: syntaxTreeViewMode) {
395396
node = sibling
396397
return true
397398
}

Sources/SwiftSyntax/RawSyntax.swift

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -993,18 +993,8 @@ final class RawSyntax: ManagedBuffer<RawSyntaxBase, RawSyntaxDataElement> {
993993
return header.totalNodes
994994
}
995995

996-
/// Whether this node is present in the original source.
997-
var isPresent: Bool {
998-
return header.isPresent
999-
}
1000-
1001-
/// Whether this node is missing from the original source.
1002-
var isMissing: Bool {
1003-
return !isPresent
1004-
}
1005-
1006996
var presence: SourcePresence {
1007-
return isPresent ? .present : .missing
997+
return header.isPresent ? .present : .missing
1008998
}
1009999

10101000
var totalLength: SourceLength {
@@ -1247,7 +1237,7 @@ extension RawSyntax: TextOutputStreamable, CustomStringConvertible {
12471237
/// - Parameter stream: The stream on which to output this node.
12481238
func write<Target>(to target: inout Target)
12491239
where Target: TextOutputStream {
1250-
guard isPresent else { return }
1240+
guard SyntaxTreeViewMode.sourceAccurate.shouldTraverse(node: self) else { return }
12511241
if isToken {
12521242
withUnsafeMutablePointers {
12531243
$0.pointee.writeToken(to: &target, extraPtr: $1)
@@ -1269,48 +1259,48 @@ extension RawSyntax: TextOutputStreamable, CustomStringConvertible {
12691259

12701260
extension RawSyntax {
12711261
/// Return the first `present` token of a layout node or self if it is a token.
1272-
var firstPresentToken: RawSyntax? {
1273-
guard isPresent else { return nil }
1262+
func firstToken(syntaxTreeViewMode: SyntaxTreeViewMode) -> RawSyntax? {
1263+
guard syntaxTreeViewMode.shouldTraverse(node: self) else { return nil }
12741264
if isToken { return self }
12751265
for i in 0..<self.numberOfChildren {
1276-
if let token = self.child(at: i)?.firstPresentToken {
1266+
if let token = self.child(at: i)?.firstToken(syntaxTreeViewMode: syntaxTreeViewMode) {
12771267
return token
12781268
}
12791269
}
12801270
return nil
12811271
}
12821272

12831273
/// Return the last `present` token of a layout node or self if it is a token.
1284-
var lastPresentToken: RawSyntax? {
1285-
guard isPresent else { return nil }
1274+
func lastToken(syntaxTreeViewMode: SyntaxTreeViewMode) -> RawSyntax? {
1275+
guard syntaxTreeViewMode.shouldTraverse(node: self) else { return nil }
12861276
if isToken { return self }
12871277
for i in (0..<self.numberOfChildren).reversed() {
1288-
if let token = self.child(at: i)?.lastPresentToken {
1278+
if let token = self.child(at: i)?.lastToken(syntaxTreeViewMode: syntaxTreeViewMode) {
12891279
return token
12901280
}
12911281
}
12921282
return nil
12931283
}
12941284

12951285
func formLeadingTrivia() -> Trivia? {
1296-
guard let token = self.firstPresentToken else { return nil }
1286+
guard let token = self.firstToken(syntaxTreeViewMode: .sourceAccurate) else { return nil }
12971287
return token.formTokenLeadingTrivia()
12981288
}
12991289

13001290
func formTrailingTrivia() -> Trivia? {
1301-
guard let token = self.lastPresentToken else { return nil }
1291+
guard let token = self.lastToken(syntaxTreeViewMode: .sourceAccurate) else { return nil }
13021292
return token.formTokenTrailingTrivia()
13031293
}
13041294
}
13051295

13061296
extension RawSyntax {
13071297
var leadingTriviaLength: SourceLength {
1308-
guard let token = self.firstPresentToken else { return .zero }
1298+
guard let token = self.firstToken(syntaxTreeViewMode: .sourceAccurate) else { return .zero }
13091299
return token.tokenLeadingTriviaLength
13101300
}
13111301

13121302
var trailingTriviaLength: SourceLength {
1313-
guard let token = self.lastPresentToken else { return .zero }
1303+
guard let token = self.lastToken(syntaxTreeViewMode: .sourceAccurate) else { return .zero }
13141304
return token.tokenTrailingTriviaLength
13151305
}
13161306

Sources/SwiftSyntax/SourceLocation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ fileprivate func computeLines(
346346
lines.append(position)
347347
}
348348
var curPrefix: SourceLength = .zero
349-
for token in tree.tokens {
349+
for token in tree.tokens(syntaxTreeViewMode: .sourceAccurate) {
350350
curPrefix = token.forEachLineLength(prefix: curPrefix, body: addLine)
351351
}
352352
position += curPrefix

Sources/SwiftSyntax/Syntax.swift

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -136,25 +136,15 @@ internal extension SyntaxProtocol {
136136

137137
public extension SyntaxProtocol {
138138
/// A sequence over the `present` children of this node.
139-
var children: SyntaxChildren {
140-
return SyntaxChildren(_syntaxNode)
139+
func children(syntaxTreeViewMode: SyntaxTreeViewMode) -> SyntaxChildren {
140+
return SyntaxChildren(_syntaxNode, syntaxTreeViewMode: syntaxTreeViewMode)
141141
}
142142

143143
/// The index of this node in a `SyntaxChildren` collection.
144144
var index: SyntaxChildrenIndex {
145145
return SyntaxChildrenIndex(self.data.absoluteRaw.info)
146146
}
147147

148-
/// Whether or not this node is marked as `present`.
149-
var isPresent: Bool {
150-
return raw.isPresent
151-
}
152-
153-
/// Whether or not this node is marked as `missing`.
154-
var isMissing: Bool {
155-
return raw.isMissing
156-
}
157-
158148
/// Whether or not this node is a token one.
159149
var isToken: Bool {
160150
return raw.isToken
@@ -190,61 +180,61 @@ public extension SyntaxProtocol {
190180

191181
/// Recursively walks through the tree to find the token semantically before
192182
/// this node.
193-
var previousToken: TokenSyntax? {
183+
func previousToken(syntaxTreeViewMode: SyntaxTreeViewMode) -> TokenSyntax? {
194184
guard let parent = self.parent else {
195185
return nil
196186
}
197-
let siblings = PresentRawSyntaxChildren(parent)
187+
let siblings = NonNilRawSyntaxChildren(parent, syntaxTreeViewMode: syntaxTreeViewMode)
198188
for absoluteRaw in siblings[..<self.index].reversed() {
199189
let child = Syntax(SyntaxData(absoluteRaw, parent: parent))
200-
if let token = child.lastToken {
190+
if let token = child.lastToken(syntaxTreeViewMode: syntaxTreeViewMode) {
201191
return token
202192
}
203193
}
204-
return parent.previousToken
194+
return parent.previousToken(syntaxTreeViewMode: syntaxTreeViewMode)
205195
}
206196

207197
/// Recursively walks through the tree to find the next token semantically
208198
/// after this node.
209-
var nextToken: TokenSyntax? {
199+
func nextToken(syntaxTreeViewMode: SyntaxTreeViewMode) -> TokenSyntax? {
210200
guard let parent = self.parent else {
211201
return nil
212202
}
213-
let siblings = PresentRawSyntaxChildren(parent)
203+
let siblings = NonNilRawSyntaxChildren(parent, syntaxTreeViewMode: syntaxTreeViewMode)
214204
let nextSiblingIndex = siblings.index(after: self.index)
215205
for absoluteRaw in siblings[nextSiblingIndex...] {
216206
let child = Syntax(SyntaxData(absoluteRaw, parent: parent))
217-
if let token = child.firstToken {
207+
if let token = child.firstToken(syntaxTreeViewMode: syntaxTreeViewMode) {
218208
return token
219209
}
220210
}
221-
return parent.nextToken
211+
return parent.nextToken(syntaxTreeViewMode: syntaxTreeViewMode)
222212
}
223213

224214
/// Returns the first token node that is part of this syntax node.
225-
var firstToken: TokenSyntax? {
226-
if isMissing { return nil }
215+
func firstToken(syntaxTreeViewMode: SyntaxTreeViewMode) -> TokenSyntax? {
216+
guard syntaxTreeViewMode.shouldTraverse(node: raw) else { return nil }
227217
if let token = _syntaxNode.as(TokenSyntax.self) {
228218
return token
229219
}
230220

231-
for child in children {
232-
if let token = child.firstToken {
221+
for child in children(syntaxTreeViewMode: syntaxTreeViewMode) {
222+
if let token = child.firstToken(syntaxTreeViewMode: syntaxTreeViewMode) {
233223
return token
234224
}
235225
}
236226
return nil
237227
}
238228

239229
/// Returns the last token node that is part of this syntax node.
240-
var lastToken: TokenSyntax? {
241-
if isMissing { return nil }
230+
func lastToken(syntaxTreeViewMode: SyntaxTreeViewMode) -> TokenSyntax? {
231+
guard syntaxTreeViewMode.shouldTraverse(node: raw) else { return nil }
242232
if let token = _syntaxNode.as(TokenSyntax.self) {
243233
return token
244234
}
245235

246-
for child in children.reversed() {
247-
if let tok = child.lastToken {
236+
for child in children(syntaxTreeViewMode: syntaxTreeViewMode).reversed() {
237+
if let tok = child.lastToken(syntaxTreeViewMode: syntaxTreeViewMode) {
248238
return tok
249239
}
250240
}
@@ -377,8 +367,8 @@ public extension SyntaxProtocol {
377367
}
378368

379369
/// Sequence of tokens that are part of this Syntax node.
380-
var tokens: TokenSequence {
381-
return TokenSequence(_syntaxNode)
370+
func tokens(syntaxTreeViewMode: SyntaxTreeViewMode) -> TokenSequence {
371+
return TokenSequence(_syntaxNode, syntaxTreeViewMode: syntaxTreeViewMode)
382372
}
383373

384374
/// Sequence of `SyntaxClassifiedRange`s for this syntax node.
@@ -466,15 +456,17 @@ public struct TokenSequence: Sequence {
466456
public struct Iterator: IteratorProtocol {
467457
var nextToken: TokenSyntax?
468458
let endPosition: AbsolutePosition
459+
let syntaxTreeViewMode: SyntaxTreeViewMode
469460

470-
init(_ token: TokenSyntax?, endPosition: AbsolutePosition) {
461+
init(_ token: TokenSyntax?, endPosition: AbsolutePosition, syntaxTreeViewMode: SyntaxTreeViewMode) {
471462
self.nextToken = token
472463
self.endPosition = endPosition
464+
self.syntaxTreeViewMode = syntaxTreeViewMode
473465
}
474466

475467
public mutating func next() -> TokenSyntax? {
476468
guard let token = self.nextToken else { return nil }
477-
self.nextToken = token.nextToken
469+
self.nextToken = token.nextToken(syntaxTreeViewMode: syntaxTreeViewMode)
478470
// Make sure we stop once we reach the end of the containing node.
479471
if let nextTok = self.nextToken, nextTok.position >= self.endPosition {
480472
self.nextToken = nil
@@ -484,17 +476,19 @@ public struct TokenSequence: Sequence {
484476
}
485477

486478
let node: Syntax
479+
let syntaxTreeViewMode: SyntaxTreeViewMode
487480

488-
public init(_ node: Syntax) {
481+
public init(_ node: Syntax, syntaxTreeViewMode: SyntaxTreeViewMode) {
489482
self.node = node
483+
self.syntaxTreeViewMode = syntaxTreeViewMode
490484
}
491485

492486
public func makeIterator() -> Iterator {
493-
return Iterator(node.firstToken, endPosition: node.endPosition)
487+
return Iterator(node.firstToken(syntaxTreeViewMode: syntaxTreeViewMode), endPosition: node.endPosition, syntaxTreeViewMode: syntaxTreeViewMode)
494488
}
495489

496490
public func reversed() -> ReversedTokenSequence {
497-
return ReversedTokenSequence(node)
491+
return ReversedTokenSequence(node, syntaxTreeViewMode: syntaxTreeViewMode)
498492
}
499493
}
500494

@@ -509,15 +503,17 @@ public struct ReversedTokenSequence: Sequence {
509503
public struct Iterator: IteratorProtocol {
510504
var nextToken: TokenSyntax?
511505
let startPosition: AbsolutePosition
506+
let syntaxTreeViewMode: SyntaxTreeViewMode
512507

513-
init(_ token: TokenSyntax?, startPosition: AbsolutePosition) {
508+
init(_ token: TokenSyntax?, startPosition: AbsolutePosition, syntaxTreeViewMode: SyntaxTreeViewMode) {
514509
self.nextToken = token
515510
self.startPosition = startPosition
511+
self.syntaxTreeViewMode = syntaxTreeViewMode
516512
}
517513

518514
public mutating func next() -> TokenSyntax? {
519515
guard let token = self.nextToken else { return nil }
520-
self.nextToken = token.previousToken
516+
self.nextToken = token.previousToken(syntaxTreeViewMode: syntaxTreeViewMode)
521517
// Make sure we stop once we went beyond the start of the containing node.
522518
if let nextTok = self.nextToken, nextTok.position < self.startPosition {
523519
self.nextToken = nil
@@ -527,17 +523,19 @@ public struct ReversedTokenSequence: Sequence {
527523
}
528524

529525
let node: Syntax
526+
let syntaxTreeViewMode: SyntaxTreeViewMode
530527

531-
public init(_ node: Syntax) {
528+
public init(_ node: Syntax, syntaxTreeViewMode: SyntaxTreeViewMode) {
532529
self.node = node
530+
self.syntaxTreeViewMode = syntaxTreeViewMode
533531
}
534532

535533
public func makeIterator() -> Iterator {
536-
return Iterator(node.lastToken, startPosition: node.position)
534+
return Iterator(node.lastToken(syntaxTreeViewMode: syntaxTreeViewMode), startPosition: node.position, syntaxTreeViewMode: syntaxTreeViewMode)
537535
}
538536

539537
public func reversed() -> TokenSequence {
540-
return TokenSequence(node)
538+
return TokenSequence(node, syntaxTreeViewMode: syntaxTreeViewMode)
541539
}
542540
}
543541

0 commit comments

Comments
 (0)