Skip to content

Commit 00cbee2

Browse files
authored
Merge pull request #1568 from ahoppen/ahoppen/basic-format-2
Some more improvements to BasicFormat + misc changes
2 parents 7650238 + 84b1372 commit 00cbee2

28 files changed

+659
-186
lines changed

CodeGeneration/Sources/SyntaxSupport/CommonNodes.swift

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ public let COMMON_NODES: [Node] = [
144144
Node(
145145
name: "MissingDecl",
146146
nameForDiagnostics: "declaration",
147+
description: "In case the source code is missing a declaration, this node stands in place of the missing declaration.",
147148
kind: "Decl",
148149
traits: [
149150
"Attributed"
@@ -152,44 +153,108 @@ public let COMMON_NODES: [Node] = [
152153
Child(
153154
name: "Attributes",
154155
kind: .collection(kind: "AttributeList", collectionElementName: "Attribute"),
156+
description: "If there were standalone attributes without a declaration to attach them to, the `MissingDeclSyntax` will contain these.",
155157
isOptional: true
156158
),
157159
Child(
158160
name: "Modifiers",
159161
kind: .collection(kind: "ModifierList", collectionElementName: "Modifier"),
162+
description: "If there were standalone modifiers without a declaration to attach them to, the `MissingDeclSyntax` will contain these.",
160163
isOptional: true
161164
),
165+
Child(
166+
name: "Placeholder",
167+
kind: .token(choices: [.token(tokenKind: "IdentifierToken")], requiresLeadingSpace: false, requiresTrailingSpace: false),
168+
description: """
169+
A placeholder, i.e. `<#decl#>` that can be inserted into the source code to represent the missing declaration.
170+
This token should always have `presence = .missing`.
171+
"""
172+
),
162173
]
163174
),
164175

165176
Node(
166177
name: "MissingExpr",
167178
nameForDiagnostics: "expression",
168-
kind: "Expr"
179+
description: "In case the source code is missing a expression, this node stands in place of the missing expression.",
180+
kind: "Expr",
181+
children: [
182+
Child(
183+
name: "Placeholder",
184+
kind: .token(choices: [.token(tokenKind: "IdentifierToken")], requiresLeadingSpace: false, requiresTrailingSpace: false),
185+
description: """
186+
A placeholder, i.e. `<#expression#>` that can be inserted into the source code to represent the missing expression.
187+
This token should always have `presence = .missing`.
188+
"""
189+
)
190+
]
169191
),
170192

171193
Node(
172194
name: "MissingPattern",
173195
nameForDiagnostics: "pattern",
174-
kind: "Pattern"
196+
description: "In case the source code is missing a pattern, this node stands in place of the missing pattern.",
197+
kind: "Pattern",
198+
children: [
199+
Child(
200+
name: "Placeholder",
201+
kind: .token(choices: [.token(tokenKind: "IdentifierToken")], requiresLeadingSpace: false, requiresTrailingSpace: false),
202+
description: """
203+
A placeholder, i.e. `<#pattern#>` that can be inserted into the source code to represent the missing pattern.
204+
This token should always have `presence = .missing`.
205+
"""
206+
)
207+
]
175208
),
176209

177210
Node(
178211
name: "MissingStmt",
179212
nameForDiagnostics: "statement",
180-
kind: "Stmt"
213+
description: "In case the source code is missing a statement, this node stands in place of the missing statement.",
214+
kind: "Stmt",
215+
children: [
216+
Child(
217+
name: "Placeholder",
218+
kind: .token(choices: [.token(tokenKind: "IdentifierToken")], requiresLeadingSpace: false, requiresTrailingSpace: false),
219+
description: """
220+
A placeholder, i.e. `<#statement#>` that can be inserted into the source code to represent the missing pattern.
221+
This token should always have `presence = .missing`.
222+
"""
223+
)
224+
]
181225
),
182226

183227
Node(
184228
name: "Missing",
185229
nameForDiagnostics: nil,
186-
kind: "Syntax"
230+
description: "In case the source code is missing a syntax node, this node stands in place of the missing node.",
231+
kind: "Syntax",
232+
children: [
233+
Child(
234+
name: "Placeholder",
235+
kind: .token(choices: [.token(tokenKind: "IdentifierToken")], requiresLeadingSpace: false, requiresTrailingSpace: false),
236+
description: """
237+
A placeholder, i.e. `<#syntax#>` that can be inserted into the source code to represent the missing pattern.
238+
This token should always have `presence = .missing`
239+
"""
240+
)
241+
]
187242
),
188243

189244
Node(
190245
name: "MissingType",
191246
nameForDiagnostics: "type",
192-
kind: "Type"
247+
description: "In case the source code is missing a type, this node stands in place of the missing type.",
248+
kind: "Type",
249+
children: [
250+
Child(
251+
name: "Placeholder",
252+
kind: .token(choices: [.token(tokenKind: "IdentifierToken")], requiresLeadingSpace: false, requiresTrailingSpace: false),
253+
description: """
254+
A placeholder, i.e. `<#type#>` that can be inserted into the source code to represent the missing type. This token should always have `presence = .missing`.
255+
"""
256+
)
257+
]
193258
),
194259

195260
Node(

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxNodesFile.swift

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ import SwiftSyntaxBuilder
1515
import SyntaxSupport
1616
import Utils
1717

18+
extension Child {
19+
public var docComment: SwiftSyntax.Trivia {
20+
guard let description = description else {
21+
return []
22+
}
23+
let dedented = dedented(string: description)
24+
let lines = dedented.split(separator: "\n", omittingEmptySubsequences: false)
25+
let pieces = lines.map { SwiftSyntax.TriviaPiece.docLineComment("/// \($0)") }
26+
return Trivia(pieces: pieces)
27+
}
28+
}
29+
1830
/// This file generates the syntax nodes for SwiftSyntax. To keep the generated
1931
/// files at a managable file size, it is to be invoked multiple times with the
2032
/// variable `emitKind` set to a base kind listed in
@@ -33,7 +45,7 @@ func syntaxNode(emitKind: String) -> SourceFileSyntax {
3345
"""
3446
) {
3547
for child in node.children {
36-
if let childChoiceDecl = try generateSyntaxChildChoices(for: child) {
48+
if let childChoiceDecl = try! generateSyntaxChildChoices(for: child) {
3749
childChoiceDecl
3850
}
3951
}
@@ -140,7 +152,7 @@ func syntaxNode(emitKind: String) -> SourceFileSyntax {
140152
if node.hasOptionalBaseTypeChild {
141153
// TODO: Remove when we no longer support compiling in Swift 5.6. Change the
142154
// above constructor to use `Optional<BaseType>.none` instead.
143-
try InitializerDeclSyntax(
155+
try! InitializerDeclSyntax(
144156
"""
145157
/// This initializer exists solely because Swift 5.6 does not support
146158
/// `Optional<ConcreteType>.none` as a default value of a generic parameter.
@@ -191,11 +203,10 @@ func syntaxNode(emitKind: String) -> SourceFileSyntax {
191203

192204
let childType: String = child.kind.isNodeChoicesEmpty ? child.typeName : child.name
193205
let type = child.isOptional ? TypeSyntax("\(raw: childType)?") : TypeSyntax("\(raw: childType)")
194-
let childDoc = child.description.map { dedented(string: $0) }.map { Trivia.docLineComment("/// \($0)") }
195206

196-
try VariableDeclSyntax(
207+
try! VariableDeclSyntax(
197208
"""
198-
\(raw: childDoc ?? [])
209+
\(raw: child.docComment)
199210
public var \(raw: child.swiftName): \(type)
200211
"""
201212
) {
@@ -274,7 +285,7 @@ private func generateSyntaxChildChoices(for child: Child) throws -> EnumDeclSynt
274285
return nil
275286
}
276287

277-
return try EnumDeclSyntax("public enum \(raw: child.name): SyntaxChildChoices") {
288+
return try! EnumDeclSyntax("public enum \(raw: child.name): SyntaxChildChoices") {
278289
for choice in choices {
279290
DeclSyntax("case `\(raw: choice.swiftName)`(\(raw: choice.typeName))")
280291
}

CodeGeneration/Sources/generate-swiftsyntax/templates/swiftsyntax/SyntaxRewriterFile.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,5 +335,17 @@ let syntaxRewriterFile = SourceFileSyntax(leadingTrivia: copyrightHeader) {
335335
}
336336
"""
337337
)
338+
339+
DeclSyntax(
340+
"""
341+
/// Rewrite `node` and anchor, making sure that the rewritten node also has
342+
/// a parent if `node` had one.
343+
public func rewrite(_ node: Syntax) -> Syntax {
344+
let rewritten = self.visit(node)
345+
let arena = SyntaxArena()
346+
return Syntax(node.data.replacingSelf(rewritten.raw, arena: arena))
347+
}
348+
"""
349+
)
338350
}
339351
}

Sources/SwiftBasicFormat/generated/BasicFormat+Extensions.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,18 @@ fileprivate extension AnyKeyPath {
245245
return false
246246
case \FunctionParameterSyntax.secondName:
247247
return true
248+
case \MissingDeclSyntax.placeholder:
249+
return false
250+
case \MissingExprSyntax.placeholder:
251+
return false
252+
case \MissingPatternSyntax.placeholder:
253+
return false
254+
case \MissingStmtSyntax.placeholder:
255+
return false
256+
case \MissingSyntax.placeholder:
257+
return false
258+
case \MissingTypeSyntax.placeholder:
259+
return false
248260
default:
249261
return nil
250262
}
@@ -262,6 +274,18 @@ fileprivate extension AnyKeyPath {
262274
return false
263275
case \DynamicReplacementArgumentsSyntax.forLabel:
264276
return false
277+
case \MissingDeclSyntax.placeholder:
278+
return false
279+
case \MissingExprSyntax.placeholder:
280+
return false
281+
case \MissingPatternSyntax.placeholder:
282+
return false
283+
case \MissingStmtSyntax.placeholder:
284+
return false
285+
case \MissingSyntax.placeholder:
286+
return false
287+
case \MissingTypeSyntax.placeholder:
288+
return false
265289
case \SwitchCaseLabelSyntax.colon:
266290
return false
267291
case \SwitchDefaultLabelSyntax.colon:

Sources/SwiftParserDiagnostics/MissingNodesError.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -335,17 +335,18 @@ extension ParseDiagnosticsGenerator {
335335

336336
/// Ancestors that don't contain any tokens are not very interesting to merge diagnostics (because there can't be any missing tokens we can merge them with).
337337
/// Find the first ancestor that contains any tokens.
338-
var ancestorWithTokens = node.parent
338+
var ancestorWithMoreTokens = node.parent
339339
var index = node.index
340-
while let unwrappedParent = ancestorWithTokens, !unwrappedParent.hasTokens {
341-
ancestorWithTokens = unwrappedParent.parent
340+
let nodeTokens = Array(node.tokens(viewMode: .all))
341+
while let unwrappedParent = ancestorWithMoreTokens, Array(unwrappedParent.tokens(viewMode: .all)) == nodeTokens {
342+
ancestorWithMoreTokens = unwrappedParent.parent
342343
index = unwrappedParent.index
343344
}
344345

345346
// Walk all upcoming sibling to see if they are also missing to handle them in this diagnostic.
346347
// If this is the case, handle all of them in this diagnostic.
347348
var missingNodes = [Syntax(node)]
348-
if let parentWithTokens = ancestorWithTokens {
349+
if let parentWithTokens = ancestorWithMoreTokens {
349350
let siblings = parentWithTokens.children(viewMode: .all)
350351
let siblingsAfter = siblings[siblings.index(after: index)...]
351352
for sibling in siblingsAfter {

Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -953,27 +953,27 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
953953
}
954954

955955
public override func visit(_ node: MissingDeclSyntax) -> SyntaxVisitorContinueKind {
956-
return handleMissingSyntax(node)
956+
return handleMissingSyntax(node, additionalHandledNodes: [node.placeholder.id])
957957
}
958958

959959
public override func visit(_ node: MissingExprSyntax) -> SyntaxVisitorContinueKind {
960-
return handleMissingSyntax(node)
960+
return handleMissingSyntax(node, additionalHandledNodes: [node.placeholder.id])
961961
}
962962

963963
public override func visit(_ node: MissingPatternSyntax) -> SyntaxVisitorContinueKind {
964-
return handleMissingSyntax(node)
964+
return handleMissingSyntax(node, additionalHandledNodes: [node.placeholder.id])
965965
}
966966

967967
public override func visit(_ node: MissingStmtSyntax) -> SyntaxVisitorContinueKind {
968-
return handleMissingSyntax(node)
968+
return handleMissingSyntax(node, additionalHandledNodes: [node.placeholder.id])
969969
}
970970

971971
public override func visit(_ node: MissingSyntax) -> SyntaxVisitorContinueKind {
972-
return handleMissingSyntax(node)
972+
return handleMissingSyntax(node, additionalHandledNodes: [node.placeholder.id])
973973
}
974974

975975
public override func visit(_ node: MissingTypeSyntax) -> SyntaxVisitorContinueKind {
976-
return handleMissingSyntax(node)
976+
return handleMissingSyntax(node, additionalHandledNodes: [node.placeholder.id])
977977
}
978978

979979
public override func visit(_ node: OperatorDeclSyntax) -> SyntaxVisitorContinueKind {

Sources/SwiftParserDiagnostics/PresenceUtils.swift

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -60,62 +60,6 @@ class PresentMaker: SyntaxRewriter {
6060
return token
6161
}
6262
}
63-
64-
override func visit(_ node: MissingDeclSyntax) -> DeclSyntax {
65-
let leadingTriviaBeforePlaceholder: Trivia
66-
if node.isMissingAllTokens {
67-
leadingTriviaBeforePlaceholder = []
68-
} else if node.modifiers != nil {
69-
leadingTriviaBeforePlaceholder = .space
70-
} else {
71-
leadingTriviaBeforePlaceholder = .newline
72-
}
73-
return DeclSyntax(
74-
StructDeclSyntax(
75-
node.unexpectedBeforeAttributes,
76-
attributes: node.attributes,
77-
node.unexpectedBetweenAttributesAndModifiers,
78-
modifiers: node.modifiers,
79-
structKeyword: .keyword(.struct, presence: .missing),
80-
identifier: .identifier("<#declaration#>", leadingTrivia: leadingTriviaBeforePlaceholder),
81-
memberBlock: MemberDeclBlockSyntax(
82-
leftBrace: .leftBraceToken(presence: .missing),
83-
members: MemberDeclListSyntax([]),
84-
rightBrace: .rightBraceToken(presence: .missing)
85-
)
86-
)
87-
)
88-
}
89-
90-
override func visit(_ node: MissingExprSyntax) -> ExprSyntax {
91-
return ExprSyntax(IdentifierExprSyntax(identifier: .identifier("<#expression#>")))
92-
}
93-
94-
override func visit(_ node: MissingPatternSyntax) -> PatternSyntax {
95-
return PatternSyntax(IdentifierPatternSyntax(identifier: .identifier("<#pattern#>")))
96-
}
97-
98-
override func visit(_ node: MissingStmtSyntax) -> StmtSyntax {
99-
return StmtSyntax(
100-
DoStmtSyntax(
101-
doKeyword: .keyword(.do, presence: .missing),
102-
UnexpectedNodesSyntax([Syntax(TokenSyntax.identifier("<#statement#>"))]),
103-
body: CodeBlockSyntax(
104-
leftBrace: .leftBraceToken(presence: .missing),
105-
statements: CodeBlockItemListSyntax([]),
106-
rightBrace: .rightBraceToken(presence: .missing)
107-
)
108-
)
109-
)
110-
}
111-
112-
override func visit(_ node: MissingTypeSyntax) -> TypeSyntax {
113-
return TypeSyntax(SimpleTypeIdentifierSyntax(name: .identifier("<#type#>")))
114-
}
115-
116-
override func visit(_ node: MissingSyntax) -> Syntax {
117-
return Syntax(IdentifierExprSyntax(identifier: .identifier("<#syntax#>")))
118-
}
11963
}
12064

12165
class MissingMaker: SyntaxRewriter {

Sources/SwiftSyntax/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ add_swift_host_library(SwiftSyntax
1212
BumpPtrAllocator.swift
1313
CommonAncestor.swift
1414
IncrementalParseTransition.swift
15+
MemoryLayout.swift
16+
MissingNodeInitializers.swift
1517
Trivia.swift
1618
SourceLength.swift
1719
SourceLocation.swift

0 commit comments

Comments
 (0)