Skip to content

Commit 0ae17dc

Browse files
committed
[Syntax] Introduce SyntaxLayout
This replaces most use case of `keyPathInParent` and `SyntaxNodeStructure.layout`. Since getting and comparing `KeyPath` is not trivial, `keyPathInParent` were suffered from performance issue, Newly introduced `SyntaxProtocol.propertyInParent` is trivial, and comparing it with a SyntaxLayoutProperty is also trivial.
1 parent 9b9765b commit 0ae17dc

18 files changed

+12884
-3809
lines changed

CodeGeneration/Sources/generate-swift-syntax/GenerateSwiftSyntax.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ struct GenerateSwiftSyntax: AsyncParsableCommand {
115115
),
116116

117117
// SwiftSyntax
118-
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["ChildNameForKeyPath.swift"], childNameForKeyPathFile),
118+
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["ConcreteSyntaxProperty.swift"], concreteSyntaxPropertyFile),
119119
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["Keyword.swift"], keywordFile),
120120
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["raw", "RawSyntaxValidation.swift"], rawSyntaxValidationFile),
121121
GeneratedFileSpec(
@@ -128,6 +128,7 @@ struct GenerateSwiftSyntax: AsyncParsableCommand {
128128
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxCollections.swift"], syntaxCollectionsFile),
129129
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxEnum.swift"], syntaxEnumFile),
130130
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxKind.swift"], syntaxKindFile),
131+
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxLayoutNodes.swift"], syntaxLayoutNodesFile),
131132
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxRewriter.swift"], syntaxRewriterFile),
132133
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["SyntaxTraits.swift"], syntaxTraitsFile),
133134
GeneratedFileSpec(

CodeGeneration/Sources/generate-swift-syntax/templates/swiftparserdiagnostics/ChildNameForDiagnosticsFile.swift

+5-5
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ let childNameForDiagnosticFile = SourceFileSyntax(leadingTrivia: copyrightHeader
2727
)
2828

2929
try! FunctionDeclSyntax(
30-
"private func childNameForDiagnostics(_ keyPath: AnyKeyPath) -> String?"
30+
"private func childNameForDiagnostics(_ property: SyntaxLayoutProperty) -> String?"
3131
) {
32-
try! SwitchExprSyntax("switch keyPath") {
32+
try! SwitchExprSyntax("switch property") {
3333
for node in NON_BASE_SYNTAX_NODES.compactMap(\.layoutNode) {
3434
for child in node.children {
3535
if let nameForDiagnostics = child.nameForDiagnostics {
36-
SwitchCaseSyntax("case \\\(node.type.syntaxBaseName).\(child.memberCallName):") {
36+
SwitchCaseSyntax("case \(node.type.syntaxBaseName).layout[.\(child.memberCallName)]:") {
3737
StmtSyntax(#"return "\#(raw: nameForDiagnostics)""#)
3838
}
3939
}
@@ -52,10 +52,10 @@ let childNameForDiagnosticFile = SourceFileSyntax(leadingTrivia: copyrightHeader
5252
"""
5353
extension SyntaxProtocol {
5454
var childNameInParent: String? {
55-
guard let keyPath = self.keyPathInParent else {
55+
guard let property = self.propertyInParent else {
5656
return nil
5757
}
58-
return childNameForDiagnostics(keyPath)
58+
return childNameForDiagnostics(property)
5959
}
6060
}
6161
"""

CodeGeneration/Sources/generate-swift-syntax/templates/swiftsyntax/ChildNameForKeyPathFile.swift

-46
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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 concreteSyntaxPropertyFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
19+
DeclSyntax(
20+
"""
21+
extension ConcreteSyntaxProperty {
22+
fileprivate init(index: UInt32) {
23+
self.index = .init(index)
24+
}
25+
}
26+
"""
27+
)
28+
29+
for node in NON_BASE_SYNTAX_NODES {
30+
if let layoutNode = node.layoutNode {
31+
try! ExtensionDeclSyntax(
32+
"\(node.apiAttributes())extension ConcreteSyntaxProperty where Base == \(node.kind.syntaxType)"
33+
) {
34+
for (index, child) in layoutNode.children.enumerated() {
35+
let childType: TypeSyntax =
36+
child.kind.isNodeChoicesEmpty
37+
? child.syntaxNodeKind.syntaxType
38+
: "\(node.kind.syntaxType).\(child.syntaxChoicesType)"
39+
let type = child.isOptional ? TypeSyntax("\(childType)?") : TypeSyntax("\(childType)")
40+
DeclSyntax(
41+
"""
42+
public static var \(child.varDeclName): ConcreteSyntaxProperty<\(node.kind.syntaxType), \(type)> {
43+
.init(index: \(raw: index))
44+
}
45+
"""
46+
)
47+
}
48+
}
49+
}
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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 syntaxLayoutNodesFile = try! SourceFileSyntax(leadingTrivia: copyrightHeader) {
19+
DeclSyntax(
20+
"""
21+
extension SyntaxLayout {
22+
fileprivate init(syntaxKind: SyntaxKind, count: UInt32) {
23+
self.syntaxKind = syntaxKind
24+
self._count = count
25+
}
26+
}
27+
"""
28+
)
29+
30+
for node in NON_BASE_SYNTAX_NODES {
31+
if let layoutNode = node.layoutNode {
32+
try! ExtensionDeclSyntax(
33+
"extension \(node.kind.syntaxType): _LayoutSyntaxProtocol"
34+
) {
35+
DeclSyntax(
36+
"""
37+
public static var layout: SyntaxLayout<Self> {
38+
SyntaxLayout<Self>(syntaxKind: .\(node.enumCaseCallName), count: \(literal: layoutNode.children.count))
39+
}
40+
"""
41+
)
42+
}
43+
}
44+
}
45+
46+
try ExtensionDeclSyntax("extension SyntaxLayoutProperty") {
47+
try VariableDeclSyntax(
48+
"""
49+
/// Property name if this is a valid property.
50+
/// 'nil' if the `syntaxKind` is not a layout syntax, or the index is out of range.
51+
@_spi(RawSyntax)
52+
public var name: String?
53+
"""
54+
) {
55+
try SwitchExprSyntax("switch (self.syntaxKind, self.index.value)") {
56+
for node in NON_BASE_SYNTAX_NODES {
57+
if let layoutNode = node.layoutNode {
58+
for (index, child) in layoutNode.children.enumerated() {
59+
SwitchCaseSyntax("case (.\(node.enumCaseCallName), \(literal: index)):") {
60+
StmtSyntax("return \(literal: child.identifier.description)")
61+
}
62+
}
63+
}
64+
}
65+
SwitchCaseSyntax("default: return nil")
66+
}
67+
}
68+
}
69+
}

Sources/SwiftBasicFormat/BasicFormat.swift

+43-45
Original file line numberDiff line numberDiff line change
@@ -188,39 +188,40 @@ open class BasicFormat: SyntaxRewriter {
188188

189189
/// Whether a leading newline on `token` should be added.
190190
open func requiresIndent(_ node: some SyntaxProtocol) -> Bool {
191-
guard let keyPath = node.keyPathInParent else {
191+
192+
guard let property = node.propertyInParent else {
192193
return false
193194
}
194-
switch keyPath {
195-
case \AccessorBlockSyntax.accessors:
195+
switch property {
196+
case AccessorBlockSyntax.layout[.accessors]:
196197
return true
197-
case \ArrayExprSyntax.elements:
198+
case ArrayExprSyntax.layout[.elements]:
198199
return true
199-
case \ClosureExprSyntax.statements:
200+
case ClosureExprSyntax.layout[.statements]:
200201
return true
201-
case \ClosureParameterClauseSyntax.parameters:
202+
case ClosureParameterClauseSyntax.layout[.parameters]:
202203
return true
203-
case \CodeBlockSyntax.statements:
204+
case CodeBlockSyntax.layout[.statements]:
204205
return true
205-
case \DictionaryElementSyntax.value:
206+
case DictionaryElementSyntax.layout[.value]:
206207
return true
207-
case \DictionaryExprSyntax.content:
208+
case DictionaryExprSyntax.layout[.content]:
208209
return true
209-
case \EnumCaseParameterClauseSyntax.parameters:
210+
case EnumCaseParameterClauseSyntax.layout[.parameters]:
210211
return true
211-
case \FunctionCallExprSyntax.arguments:
212+
case FunctionCallExprSyntax.layout[.arguments]:
212213
return true
213-
case \FunctionTypeSyntax.parameters:
214+
case FunctionTypeSyntax.layout[.parameters]:
214215
return true
215-
case \MemberDeclBlockSyntax.members:
216+
case MemberBlockSyntax.layout[.members]:
216217
return true
217-
case \ParameterClauseSyntax.parameters:
218+
case FunctionParameterClauseSyntax.layout[.parameters]:
218219
return true
219-
case \SwitchCaseSyntax.statements:
220+
case SwitchCaseSyntax.layout[.statements]:
220221
return true
221-
case \TupleExprSyntax.elements:
222+
case TupleExprSyntax.layout[.elements]:
222223
return true
223-
case \TupleTypeSyntax.elements:
224+
case TupleTypeSyntax.layout[.elements]:
224225
return true
225226
default:
226227
return false
@@ -234,17 +235,17 @@ open class BasicFormat: SyntaxRewriter {
234235
/// as a closure or if it gets interpreted as the statements body. We should
235236
/// thus be conservative and not add a newline after the `{` in `BasicFormat`.
236237
private func isLeftBraceOfClosureInStmtConditionExpr(_ token: TokenSyntax?) -> Bool {
237-
guard let token, token.keyPathInParent == \ClosureExprSyntax.leftBrace else {
238+
guard let token, token.propertyInParent == ClosureExprSyntax.layout[.leftBrace] else {
238239
return false
239240
}
240241
return token.ancestorOrSelf(mapping: {
241-
switch $0.keyPathInParent {
242-
case \CatchItemSyntax.pattern,
243-
\ConditionElementSyntax.condition,
244-
\ExpressionPatternSyntax.expression,
245-
\ForStmtSyntax.sequence,
246-
\ForStmtSyntax.whereClause,
247-
\SwitchExprSyntax.subject:
242+
switch $0.propertyInParent {
243+
case CatchItemSyntax.layout[.pattern],
244+
ConditionElementSyntax.layout[.condition],
245+
ExpressionPatternSyntax.layout[.expression],
246+
ForStmtSyntax.layout[.sequence],
247+
ForStmtSyntax.layout[.whereClause],
248+
SwitchExprSyntax.layout[.subject]:
248249
return $0
249250
default:
250251
return nil
@@ -275,11 +276,8 @@ open class BasicFormat: SyntaxRewriter {
275276
if let ancestorsParent = ancestor.parent, childrenSeparatedByNewline(ancestorsParent) {
276277
return true
277278
}
278-
switch ancestor.keyPathInParent {
279-
case \IfConfigClauseSyntax.elements:
279+
if ancestor.propertyInParent == IfConfigClauseSyntax.layout[.elements] {
280280
return true
281-
default:
282-
break
283281
}
284282
}
285283
}
@@ -363,9 +361,9 @@ open class BasicFormat: SyntaxRewriter {
363361
(nil, _):
364362
return false
365363
case (_, .colon):
366-
switch second?.keyPathInParent {
367-
case \TernaryExprSyntax.colon,
368-
\UnresolvedTernaryExprSyntax.colon:
364+
switch second?.propertyInParent {
365+
case TernaryExprSyntax.layout[.colon],
366+
UnresolvedTernaryExprSyntax.layout[.colon]:
369367
break
370368
default:
371369
return false
@@ -377,12 +375,12 @@ open class BasicFormat: SyntaxRewriter {
377375
// `<` and `>` need to be separated by a space because otherwise they become an operator
378376
return false
379377
case (_, .leftParen):
380-
switch second?.keyPathInParent {
381-
case \ClosureParameterClauseSyntax.leftParen,
382-
\FunctionTypeSyntax.leftParen,
383-
\TupleExprSyntax.leftParen,
384-
\TuplePatternSyntax.leftParen,
385-
\TupleTypeSyntax.leftParen:
378+
switch second?.propertyInParent {
379+
case ClosureParameterClauseSyntax.layout[.leftParen],
380+
FunctionTypeSyntax.layout[.leftParen],
381+
TupleExprSyntax.layout[.leftParen],
382+
TuplePatternSyntax.layout[.leftParen],
383+
TupleTypeSyntax.layout[.leftParen]:
386384
break
387385
default:
388386
return false
@@ -392,13 +390,13 @@ open class BasicFormat: SyntaxRewriter {
392390
break
393391
}
394392

395-
switch first?.keyPathInParent {
396-
case \ExpressionSegmentSyntax.backslash,
397-
\ExpressionSegmentSyntax.rightParen,
398-
\DeclNameArgumentSyntax.colon,
399-
\SimpleStringLiteralExprSyntax.openingQuote,
400-
\StringLiteralExprSyntax.openingQuote,
401-
\RegexLiteralExprSyntax.openingSlash:
393+
switch first?.propertyInParent {
394+
case ExpressionSegmentSyntax.layout[.backslash],
395+
ExpressionSegmentSyntax.layout[.rightParen],
396+
DeclNameArgumentSyntax.layout[.colon],
397+
SimpleStringLiteralExprSyntax.layout[.openingQuote],
398+
StringLiteralExprSyntax.layout[.openingQuote],
399+
RegexLiteralExprSyntax.layout[.openingSlash]:
402400
return false
403401
default:
404402
break

Sources/SwiftCompilerPluginMessageHandling/CompilerPluginMessageHandler.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ nonisolated(unsafe) private var readabilityHandler: () -> Void = {
263263
)
264264
}
265265

266-
@_expose(wasm, "swift_wasm_macro_v1_pump")
266+
@_expose(wasm,"swift_wasm_macro_v1_pump")
267267
@_cdecl("swift_wasm_macro_v1_pump")
268268
func wasmPump() {
269269
readabilityHandler()

0 commit comments

Comments
 (0)