Skip to content

Commit 12c38a5

Browse files
committed
[Syntax] Introduce SyntaxLayout
1 parent cdff432 commit 12c38a5

File tree

8 files changed

+9252
-225
lines changed

8 files changed

+9252
-225
lines changed

Diff for: CodeGeneration/Sources/generate-swift-syntax/GenerateSwiftSyntax.swift

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ struct GenerateSwiftSyntax: AsyncParsableCommand {
116116

117117
// SwiftSyntax
118118
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["ChildNameForKeyPath.swift"], childNameForKeyPathFile),
119+
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["ConcreteSyntaxProperty.swift"], concreteSyntaxPropertyFile),
119120
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["Keyword.swift"], keywordFile),
120121
GeneratedFileSpec(swiftSyntaxGeneratedDir + ["raw", "RawSyntaxValidation.swift"], rawSyntaxValidationFile),
121122
GeneratedFileSpec(

Diff for: 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.varOrCaseName):") {
36+
SwitchCaseSyntax("case \(node.type.syntaxBaseName).layout[.\(child.varOrCaseName)]:") {
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
"""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
extension SyntaxLayout {
21+
fileprivate init(kind: SyntaxKind, count: UInt32) {
22+
self.kind = kind
23+
self._count = count
24+
}
25+
}
26+
""")
27+
28+
DeclSyntax("""
29+
extension ConcreteSyntaxProperty {
30+
fileprivate init(index: UInt32) {
31+
self.index = .init(index)
32+
}
33+
}
34+
""")
35+
36+
for node in NON_BASE_SYNTAX_NODES {
37+
if let layoutNode = node.layoutNode {
38+
try! ExtensionDeclSyntax(
39+
"extension \(node.kind.syntaxType): _LayoutSyntaxProtocol"
40+
) {
41+
DeclSyntax("""
42+
public static var layout: SyntaxLayout<Self> {
43+
SyntaxLayout<Self>(kind: .\(node.kind.varOrCaseName), count: \(literal: layoutNode.children.count))
44+
}
45+
""")
46+
}
47+
try! ExtensionDeclSyntax(
48+
"\(node.apiAttributes())extension ConcreteSyntaxProperty where Base == \(node.kind.syntaxType)"
49+
) {
50+
for (index, child) in layoutNode.children.enumerated() {
51+
let childType: TypeSyntax = child.kind.isNodeChoicesEmpty
52+
? child.syntaxNodeKind.syntaxType
53+
: "\(node.kind.syntaxType).\(child.syntaxChoicesType)"
54+
let type = child.isOptional ? TypeSyntax("\(childType)?") : TypeSyntax("\(childType)")
55+
DeclSyntax("""
56+
public static var \(child.varOrCaseName.backtickedIfNeeded): ConcreteSyntaxProperty<\(node.kind.syntaxType), \(type)> {
57+
.init(index: \(raw: index))
58+
}
59+
""")
60+
}
61+
}
62+
}
63+
}
64+
}

Diff for: Sources/SwiftBasicFormat/BasicFormat.swift

+44-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,18 @@ 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
244+
CatchItemSyntax.layout[.pattern],
245+
ConditionElementSyntax.layout[.condition],
246+
ExpressionPatternSyntax.layout[.expression],
247+
ForStmtSyntax.layout[.sequence],
248+
ForStmtSyntax.layout[.whereClause],
249+
SwitchExprSyntax.layout[.subject]:
248250
return $0
249251
default:
250252
return nil
@@ -275,11 +277,8 @@ open class BasicFormat: SyntaxRewriter {
275277
if let ancestorsParent = ancestor.parent, childrenSeparatedByNewline(ancestorsParent) {
276278
return true
277279
}
278-
switch ancestor.keyPathInParent {
279-
case \IfConfigClauseSyntax.elements:
280+
if ancestor.propertyInParent == IfConfigClauseSyntax.layout[.elements] {
280281
return true
281-
default:
282-
break
283282
}
284283
}
285284
}
@@ -363,9 +362,9 @@ open class BasicFormat: SyntaxRewriter {
363362
(nil, _):
364363
return false
365364
case (_, .colon):
366-
switch second?.keyPathInParent {
367-
case \TernaryExprSyntax.colon,
368-
\UnresolvedTernaryExprSyntax.colon:
365+
switch second?.propertyInParent {
366+
case TernaryExprSyntax.layout[.colon],
367+
UnresolvedTernaryExprSyntax.layout[.colon]:
369368
break
370369
default:
371370
return false
@@ -377,12 +376,12 @@ open class BasicFormat: SyntaxRewriter {
377376
// `<` and `>` need to be separated by a space because otherwise they become an operator
378377
return false
379378
case (_, .leftParen):
380-
switch second?.keyPathInParent {
381-
case \ClosureParameterClauseSyntax.leftParen,
382-
\FunctionTypeSyntax.leftParen,
383-
\TupleExprSyntax.leftParen,
384-
\TuplePatternSyntax.leftParen,
385-
\TupleTypeSyntax.leftParen:
379+
switch second?.propertyInParent {
380+
case ClosureParameterClauseSyntax.layout[.leftParen],
381+
FunctionTypeSyntax.layout[.leftParen],
382+
TupleExprSyntax.layout[.leftParen],
383+
TuplePatternSyntax.layout[.leftParen],
384+
TupleTypeSyntax.layout[.leftParen]:
386385
break
387386
default:
388387
return false
@@ -392,13 +391,13 @@ open class BasicFormat: SyntaxRewriter {
392391
break
393392
}
394393

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

0 commit comments

Comments
 (0)