Skip to content

Commit d2a1060

Browse files
authored
Merge pull request #1482 from ahoppen/ahoppen/swiftsyntax-public-api
Audit the public API of the SwiftSyntax module
2 parents 1ca3d9e + 84358d0 commit d2a1060

File tree

61 files changed

+2365
-7331
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+2365
-7331
lines changed

CodeGeneration/Sources/SyntaxSupport/Classification.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,15 @@ public class SyntaxClassification {
2828
public class ChildClassification {
2929
public let parent: Node
3030
public let childIndex: Int
31-
public let isToken: Bool
32-
public let classification: SyntaxClassification?
33-
public let force: Bool
31+
public let child: Child
32+
public var isToken: Bool { child.isToken }
33+
public var classification: SyntaxClassification? { child.classification }
34+
public var force: Bool { child.forceClassification }
3435

3536
public init(node: Node, childIndex: Int, child: Child) {
3637
self.parent = node
3738
self.childIndex = childIndex
38-
self.isToken = child.syntaxKind.hasSuffix("Token")
39-
self.classification = child.classification
40-
self.force = child.forceClassification
39+
self.child = child
4140
}
4241
}
4342

CodeGeneration/Sources/generate-swiftsyntax/GenerateSwiftSyntax.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ private let generatedDirName = "generated"
2222
private let swiftBasicFormatGeneratedDir = ["SwiftBasicFormat", generatedDirName]
2323
private let ideUtilsGeneratedDir = ["IDEUtils", generatedDirName]
2424
private let swiftParserGeneratedDir = ["SwiftParser", generatedDirName]
25+
private let swiftParserDiagnosticsGeneratedDir = ["SwiftParserDiagnostics", generatedDirName]
2526
private let swiftSyntaxGeneratedDir = ["SwiftSyntax", generatedDirName]
2627
private let swiftSyntaxBuilderGeneratedDir = ["SwiftSyntaxBuilder", generatedDirName]
2728
private let BASE_KIND_FILES = [
@@ -86,13 +87,18 @@ struct GenerateSwiftSyntax: ParsableCommand {
8687

8788
// SwiftParser
8889
GeneratedFileSpec(swiftParserGeneratedDir + ["DeclarationModifier.swift"], declarationModifierFile),
90+
GeneratedFileSpec(swiftParserGeneratedDir + ["IsLexerClassified.swift"], isLexerClassifiedFile),
8991
GeneratedFileSpec(swiftParserGeneratedDir + ["Parser+Entry.swift"], parserEntryFile),
9092
GeneratedFileSpec(swiftParserGeneratedDir + ["TokenSpecStaticMembers.swift"], tokenSpecStaticMembersFile),
9193
GeneratedFileSpec(swiftParserGeneratedDir + ["TypeAttribute.swift"], typeAttributeFile),
9294

95+
// SwiftParserDiagnostics
96+
GeneratedFileSpec(swiftParserDiagnosticsGeneratedDir + ["ChildNameForDiagnostics.swift"], childNameForDiagnosticFile),
97+
GeneratedFileSpec(swiftParserDiagnosticsGeneratedDir + ["SyntaxKindNameForDiagnostics.swift"], syntaxKindNameForDiagnosticFile),
98+
GeneratedFileSpec(swiftParserDiagnosticsGeneratedDir + ["TokenNameForDiagnostics.swift"], tokenNameForDiagnosticFile),
99+
93100
// SwiftSyntax
94101
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["Keyword.swift"], keywordFile),
95-
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["Misc.swift"], miscFile),
96102
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["raw", "RawSyntaxNodes.swift"], rawSyntaxNodesFile),
97103
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["raw", "RawSyntaxValidation.swift"], rawSyntaxValidationFile),
98104
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxAnyVisitor.swift"], syntaxAnyVisitorFile),

CodeGeneration/Sources/generate-swiftsyntax/templates/basicformat/BasicFormatFile.swift

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,19 @@ let basicFormatFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
6262
DeclSyntax(
6363
"""
6464
open override func visitPre(_ node: Syntax) {
65-
if let keyPath = getKeyPath(node), shouldIndent(keyPath) {
65+
if let keyPath = node.keyPathInParent, shouldIndent(keyPath) {
6666
indentationLevel += 1
6767
}
6868
if let parent = node.parent, childrenSeparatedByNewline(parent) {
69-
putNextTokenOnNewLine = true && node.previousToken != nil
69+
putNextTokenOnNewLine = true && node.previousToken(viewMode: .sourceAccurate) != nil
7070
}
7171
}
7272
"""
7373
)
7474
DeclSyntax(
7575
"""
7676
open override func visitPost(_ node: Syntax) {
77-
if let keyPath = getKeyPath(node), shouldIndent(keyPath) {
77+
if let keyPath = node.keyPathInParent, shouldIndent(keyPath) {
7878
indentationLevel -= 1
7979
}
8080
}
@@ -92,7 +92,7 @@ let basicFormatFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
9292
if requiresTrailingSpace(node) && trailingTrivia.isEmpty {
9393
trailingTrivia += .space
9494
}
95-
if let keyPath = getKeyPath(Syntax(node)), requiresLeadingNewline(keyPath), !(leadingTrivia.first?.isNewline ?? false), !shouldOmitNewline(node) {
95+
if let keyPath = node.keyPathInParent, requiresLeadingNewline(keyPath), !(leadingTrivia.first?.isNewline ?? false), !shouldOmitNewline(node) {
9696
leadingTrivia = .newline + leadingTrivia
9797
}
9898
var isOnNewline: Bool = (lastRewrittenToken?.trailingTrivia.pieces.last?.isNewline == true)
@@ -206,7 +206,7 @@ let basicFormatFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
206206
try FunctionDeclSyntax("open func requiresLeadingSpace(_ token: TokenSyntax) -> Bool") {
207207
StmtSyntax(
208208
"""
209-
if let keyPath = getKeyPath(token), let requiresLeadingSpace = requiresLeadingSpace(keyPath) {
209+
if let keyPath = token.keyPathInParent, let requiresLeadingSpace = requiresLeadingSpace(keyPath) {
210210
return requiresLeadingSpace
211211
}
212212
"""
@@ -268,7 +268,7 @@ let basicFormatFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
268268
try FunctionDeclSyntax("open func requiresTrailingSpace(_ token: TokenSyntax) -> Bool") {
269269
StmtSyntax(
270270
"""
271-
if let keyPath = getKeyPath(token), let requiresTrailingSpace = requiresTrailingSpace(keyPath) {
271+
if let keyPath = token.keyPathInParent, let requiresTrailingSpace = requiresTrailingSpace(keyPath) {
272272
return requiresTrailingSpace
273273
}
274274
"""
@@ -311,19 +311,5 @@ let basicFormatFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
311311
}
312312
}
313313
}
314-
315-
DeclSyntax(
316-
"""
317-
private func getKeyPath<T: SyntaxProtocol>(_ node: T) -> AnyKeyPath? {
318-
guard let parent = node.parent else {
319-
return nil
320-
}
321-
guard case .layout(let childrenKeyPaths) = parent.kind.syntaxNodeType.structure else {
322-
return nil
323-
}
324-
return childrenKeyPaths[node.indexInParent]
325-
}
326-
"""
327-
)
328314
}
329315
}

CodeGeneration/Sources/generate-swiftsyntax/templates/ideutils/SyntaxClassificationFile.swift

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -53,35 +53,17 @@ let syntaxClassificationFile = SourceFileSyntax(leadingTrivia: copyrightHeader)
5353
/// - childKind: The node syntax kind.
5454
/// - Returns: A pair of classification and whether it is "forced", or nil if
5555
/// no classification is attached.
56-
internal static func classify(
57-
parentKind: SyntaxKind, indexInParent: Int, childKind: SyntaxKind
58-
) -> (SyntaxClassification, Bool)?
56+
internal static func classify(_ keyPath: AnyKeyPath) -> (SyntaxClassification, Bool)?
5957
"""
6058
) {
61-
try IfExprSyntax(
62-
"""
63-
// Separate checks for token nodes (most common checks) versus checks for layout nodes.
64-
if childKind == .token
65-
"""
66-
) {
67-
try SwitchExprSyntax("switch (parentKind, indexInParent)") {
68-
for childClassification in node_child_classifications where childClassification.isToken {
69-
SwitchCaseSyntax("case (.\(raw: childClassification.parent.swiftSyntaxKind), \(raw: childClassification.childIndex)):") {
70-
StmtSyntax("return (.\(raw: childClassification.classification!.swiftName), \(raw: childClassification.force))")
71-
}
59+
try SwitchExprSyntax("switch keyPath") {
60+
for childClassification in node_child_classifications {
61+
SwitchCaseSyntax("case \\\(raw: childClassification.parent.type.syntaxBaseName).\(raw: childClassification.child.swiftName):") {
62+
StmtSyntax("return (.\(raw: childClassification.classification!.swiftName), \(raw: childClassification.force))")
7263
}
73-
74-
SwitchCaseSyntax("default: return nil")
7564
}
76-
} else: {
77-
try SwitchExprSyntax("switch (parentKind, indexInParent)") {
78-
for childClassification in node_child_classifications where !childClassification.isToken {
79-
SwitchCaseSyntax("case (.\(raw: childClassification.parent.swiftSyntaxKind), \(raw: childClassification.childIndex)):") {
80-
StmtSyntax("return (.\(raw: childClassification.classification!.swiftName), \(raw: childClassification.force))")
81-
}
82-
}
83-
84-
SwitchCaseSyntax("default: return nil")
65+
SwitchCaseSyntax("default:") {
66+
StmtSyntax("return nil")
8567
}
8668
}
8769
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 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+
import SwiftSyntax
14+
import SwiftSyntaxBuilder
15+
import SyntaxSupport
16+
import Utils
17+
18+
let isLexerClassifiedFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
19+
DeclSyntax("import SwiftSyntax")
20+
21+
try! ExtensionDeclSyntax(
22+
"""
23+
extension Keyword
24+
"""
25+
) {
26+
try! VariableDeclSyntax(
27+
"""
28+
/// Whether the token kind is switched from being an identifier to being a keyword in the lexer.
29+
/// This is true for keywords that used to be considered non-contextual.
30+
var isLexerClassified: Bool
31+
"""
32+
) {
33+
try! SwitchExprSyntax("switch self") {
34+
for keyword in KEYWORDS {
35+
if keyword.isLexerClassified {
36+
SwitchCaseSyntax("case .\(raw: keyword.escapedName): return true")
37+
}
38+
}
39+
SwitchCaseSyntax("default: return false")
40+
}
41+
}
42+
}
43+
44+
try! ExtensionDeclSyntax(
45+
"""
46+
extension TokenKind
47+
"""
48+
) {
49+
try! VariableDeclSyntax(
50+
"""
51+
/// Returns `true` if the token is a Swift keyword.
52+
///
53+
/// Keywords are reserved unconditionally for use by Swift and may not
54+
/// appear as identifiers in any position without being escaped. For example,
55+
/// `class`, `func`, or `import`.
56+
public var isLexerClassifiedKeyword: Bool
57+
"""
58+
) {
59+
try! SwitchExprSyntax("switch self") {
60+
SwitchCaseSyntax("case .eof:") {
61+
StmtSyntax("return false")
62+
}
63+
64+
for token in SYNTAX_TOKENS where token.isKeyword {
65+
SwitchCaseSyntax("case .\(raw: token.swiftKind):") {
66+
StmtSyntax("return true")
67+
}
68+
}
69+
70+
SwitchCaseSyntax("case .keyword(let keyword):") {
71+
StmtSyntax("return keyword.isLexerClassified")
72+
}
73+
SwitchCaseSyntax("default: return false")
74+
}
75+
}
76+
}
77+
}

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftparser/TokenSpecStaticMembersFile.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import SyntaxSupport
1616
import Utils
1717

1818
let tokenSpecStaticMembersFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
19-
DeclSyntax("import SwiftSyntax")
19+
DeclSyntax("@_spi(RawSyntax) import SwiftSyntax")
2020

2121
try! ExtensionDeclSyntax("extension TokenSpec") {
2222
DeclSyntax("static var eof: TokenSpec { return TokenSpec(.eof) }")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 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+
import SwiftSyntax
14+
import SwiftSyntaxBuilder
15+
import SyntaxSupport
16+
import Utils
17+
18+
let childNameForDiagnosticFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
19+
DeclSyntax("import SwiftSyntax")
20+
21+
try! FunctionDeclSyntax(
22+
"private func childNameForDiagnostics(_ keyPath: AnyKeyPath) -> String?"
23+
) {
24+
try! SwitchExprSyntax("switch keyPath") {
25+
for node in NON_BASE_SYNTAX_NODES where !node.isSyntaxCollection {
26+
for child in node.children {
27+
if let nameForDiagnostics = child.nameForDiagnostics {
28+
SwitchCaseSyntax("case \\\(raw: node.type.syntaxBaseName).\(raw: child.swiftName):") {
29+
StmtSyntax(#"return "\#(raw: nameForDiagnostics)""#)
30+
}
31+
}
32+
}
33+
}
34+
SwitchCaseSyntax(
35+
"""
36+
default:
37+
return nil
38+
"""
39+
)
40+
}
41+
}
42+
43+
DeclSyntax(
44+
"""
45+
extension SyntaxProtocol {
46+
var childNameInParent: String? {
47+
guard let keyPath = self.keyPathInParent else {
48+
return nil
49+
}
50+
return childNameForDiagnostics(keyPath)
51+
}
52+
}
53+
"""
54+
)
55+
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 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+
import SwiftSyntax
14+
import SwiftSyntaxBuilder
15+
import SyntaxSupport
16+
import Utils
17+
18+
let syntaxKindNameForDiagnosticFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
19+
DeclSyntax("import SwiftSyntax")
20+
21+
try! ExtensionDeclSyntax("extension SyntaxKind") {
22+
try VariableDeclSyntax("var nameForDiagnostics: String?") {
23+
try SwitchExprSyntax("switch self") {
24+
SwitchCaseSyntax("case .token:") {
25+
StmtSyntax(#"return "token""#)
26+
}
27+
28+
for node in NON_BASE_SYNTAX_NODES {
29+
if let nameForDiagnostics = node.nameForDiagnostics {
30+
SwitchCaseSyntax("case .\(raw: node.swiftSyntaxKind):") {
31+
StmtSyntax("return \"\(raw: nameForDiagnostics)\"")
32+
}
33+
}
34+
}
35+
SwitchCaseSyntax(
36+
"""
37+
default:
38+
return nil
39+
"""
40+
)
41+
}
42+
}
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 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+
import SwiftSyntax
14+
import SwiftSyntaxBuilder
15+
import SyntaxSupport
16+
import Utils
17+
18+
let tokenNameForDiagnosticFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
19+
DeclSyntax("@_spi(RawSyntax) import SwiftSyntax")
20+
21+
try! ExtensionDeclSyntax("extension TokenKind") {
22+
try! VariableDeclSyntax("var nameForDiagnostics: String") {
23+
try! SwitchExprSyntax("switch self") {
24+
SwitchCaseSyntax("case .eof:") {
25+
StmtSyntax(#"return "end of file""#)
26+
}
27+
28+
for token in SYNTAX_TOKENS where token.swiftKind != "keyword" {
29+
SwitchCaseSyntax("case .\(raw: token.swiftKind):") {
30+
StmtSyntax("return #\"\(raw: token.nameForDiagnostics)\"#")
31+
}
32+
}
33+
SwitchCaseSyntax("case .keyword(let keyword):") {
34+
StmtSyntax("return String(syntaxText: keyword.defaultText)")
35+
}
36+
}
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)