Skip to content

Commit 1afd737

Browse files
committed
Simplify BasicFormat
1 parent 753d0c1 commit 1afd737

File tree

4 files changed

+400
-3252
lines changed

4 files changed

+400
-3252
lines changed

CodeGeneration/Sources/generate-swiftbasicformat/BasicFormatFile.swift

Lines changed: 211 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,221 @@ let basicFormatFile = SourceFile {
2727
VariableDecl("open var indentation: TriviaPiece { .spaces(indentationLevel * 4) }")
2828
VariableDecl("public var indentedNewline: Trivia { Trivia(pieces: [.newlines(1), indentation]) }")
2929
VariableDecl("private var lastRewrittenToken: TokenSyntax?")
30+
VariableDecl("private var putNextTokenOnNewLine: Bool = false")
3031

31-
for node in SYNTAX_NODES where !node.isBase {
32-
if node.isSyntaxCollection {
33-
makeSyntaxCollectionRewriteFunc(node: node)
34-
} else {
35-
makeLayoutNodeRewriteFunc(node: node)
32+
FunctionDecl("""
33+
open override func visitPre(_ node: Syntax) {
34+
if let keyPath = getKeyPath(node), shouldIndent(keyPath) {
35+
indentationLevel += 1
36+
}
37+
if let parent = node.parent, childrenSeparatedByNewline(parent) {
38+
putNextTokenOnNewLine = true
39+
}
40+
}
41+
"""
42+
)
43+
FunctionDecl("""
44+
open override func visitPost(_ node: Syntax) {
45+
if let keyPath = getKeyPath(node), shouldIndent(keyPath) {
46+
indentationLevel -= 1
47+
}
48+
}
49+
"""
50+
)
51+
52+
FunctionDecl("""
53+
open override func visit(_ node: TokenSyntax) -> TokenSyntax {
54+
var leadingTrivia = node.leadingTrivia
55+
var trailingTrivia = node.trailingTrivia
56+
if requiresLeadingSpace(node.tokenKind) && leadingTrivia.isEmpty && lastRewrittenToken?.trailingTrivia.isEmpty != false {
57+
leadingTrivia += .space
58+
}
59+
if requiresTrailingSpace(node.tokenKind) && trailingTrivia.isEmpty {
60+
trailingTrivia += .space
61+
}
62+
if let keyPath = getKeyPath(Syntax(node)), requiresLeadingNewline(keyPath), !(leadingTrivia.first?.isNewline ?? false) {
63+
leadingTrivia = .newline + leadingTrivia
64+
}
65+
leadingTrivia = leadingTrivia.indented(indentation: indentation)
66+
trailingTrivia = trailingTrivia.indented(indentation: indentation)
67+
let rewritten = TokenSyntax(
68+
node.tokenKind,
69+
leadingTrivia: leadingTrivia,
70+
trailingTrivia: trailingTrivia,
71+
presence: node.presence
72+
)
73+
lastRewrittenToken = rewritten
74+
putNextTokenOnNewLine = false
75+
return rewritten
76+
}
77+
"""
78+
)
79+
80+
FunctionDecl(
81+
modifiers: [DeclModifier(name: .open)],
82+
identifier: .identifier("shouldIndent"),
83+
signature: FunctionSignature(
84+
input: ParameterClause(parameterList: [
85+
FunctionParameter(
86+
firstName: Token.wildcard,
87+
secondName: .identifier("keyPath"),
88+
colon: .colon,
89+
type: SimpleTypeIdentifier("AnyKeyPath")
90+
91+
)
92+
]),
93+
output: ReturnClause(returnType: SimpleTypeIdentifier("Bool"))
94+
)
95+
) {
96+
SwitchStmt(expression: Expr("keyPath")) {
97+
for node in SYNTAX_NODES where !node.isBase {
98+
for child in node.children where child.isIndented {
99+
SwitchCase(label: SwitchCaseLabel(caseItems: [CaseItem(pattern: ExpressionPattern(expression: KeyPathExpr("\\\(node.type.syntaxBaseName).\(child.swiftName)")))])) {
100+
ReturnStmt("return true")
101+
}
102+
}
103+
}
104+
SwitchCase(label: SwitchDefaultLabel()) {
105+
ReturnStmt("return false")
106+
}
107+
}
108+
}
109+
110+
FunctionDecl(
111+
modifiers: [DeclModifier(name: .open)],
112+
identifier: .identifier("requiresLeadingNewline"),
113+
signature: FunctionSignature(
114+
input: ParameterClause(parameterList: [
115+
FunctionParameter(
116+
firstName: Token.wildcard,
117+
secondName: .identifier("keyPath"),
118+
colon: .colon,
119+
type: SimpleTypeIdentifier("AnyKeyPath")
120+
121+
)
122+
]),
123+
output: ReturnClause(returnType: SimpleTypeIdentifier("Bool"))
124+
)
125+
) {
126+
SwitchStmt(expression: Expr("keyPath")) {
127+
for node in SYNTAX_NODES where !node.isBase {
128+
for child in node.children where child.requiresLeadingNewline {
129+
SwitchCase(label: SwitchCaseLabel(caseItems: [CaseItem(pattern: ExpressionPattern(expression: KeyPathExpr("\\\(node.type.syntaxBaseName).\(child.swiftName)")))])) {
130+
ReturnStmt("return true")
131+
}
132+
}
133+
}
134+
SwitchCase(label: SwitchDefaultLabel()) {
135+
ReturnStmt("return putNextTokenOnNewLine")
136+
}
137+
}
138+
}
139+
140+
FunctionDecl(
141+
modifiers: [DeclModifier(name: .open)],
142+
identifier: .identifier("childrenSeparatedByNewline"),
143+
signature: FunctionSignature(
144+
input: ParameterClause(parameterList: [
145+
FunctionParameter(
146+
firstName: Token.wildcard,
147+
secondName: .identifier("node"),
148+
colon: .colon,
149+
type: SimpleTypeIdentifier("Syntax")
150+
151+
)
152+
]),
153+
output: ReturnClause(returnType: SimpleTypeIdentifier("Bool"))
154+
)
155+
) {
156+
SwitchStmt(expression: Expr("node.as(SyntaxEnum.self)")) {
157+
for node in SYNTAX_NODES where !node.isBase {
158+
if node.elementsSeparatedByNewline {
159+
SwitchCase(label: SwitchCaseLabel(caseItems: [CaseItem(pattern: ExpressionPattern(expression: MemberAccessExpr(".\(node.swiftSyntaxKind)")))])) {
160+
ReturnStmt("return true")
161+
}
162+
}
163+
}
164+
SwitchCase(label: SwitchDefaultLabel()) {
165+
ReturnStmt("return false")
166+
}
167+
}
168+
}
169+
170+
FunctionDecl(
171+
modifiers: [DeclModifier(name: .open)],
172+
identifier: .identifier("requiresLeadingSpace"),
173+
signature: FunctionSignature(
174+
input: ParameterClause(parameterList: [
175+
FunctionParameter(
176+
firstName: Token.wildcard,
177+
secondName: .identifier("tokenKind"),
178+
colon: .colon,
179+
type: SimpleTypeIdentifier("TokenKind")
180+
181+
)
182+
]),
183+
output: ReturnClause(returnType: SimpleTypeIdentifier("Bool"))
184+
)
185+
) {
186+
SwitchStmt(expression: Expr("tokenKind")) {
187+
for token in SYNTAX_TOKENS {
188+
if token.requiresLeadingSpace {
189+
SwitchCase(label: SwitchCaseLabel(caseItems: [CaseItem(pattern: ExpressionPattern(expression: MemberAccessExpr(".\(token.swiftKind)")))])) {
190+
ReturnStmt("return true")
191+
}
192+
}
193+
}
194+
SwitchCase(label: SwitchDefaultLabel()) {
195+
ReturnStmt("return false")
196+
}
36197
}
37198
}
38199

39-
createTokenFormatFunction()
200+
FunctionDecl(
201+
modifiers: [DeclModifier(name: .open)],
202+
identifier: .identifier("requiresTrailingSpace"),
203+
signature: FunctionSignature(
204+
input: ParameterClause(parameterList: [
205+
FunctionParameter(
206+
firstName: Token.wildcard,
207+
secondName: .identifier("tokenKind"),
208+
colon: .colon,
209+
type: SimpleTypeIdentifier("TokenKind")
210+
211+
)
212+
]),
213+
output: ReturnClause(returnType: SimpleTypeIdentifier("Bool"))
214+
)
215+
) {
216+
SwitchStmt(expression: Expr("tokenKind")) {
217+
for token in SYNTAX_TOKENS {
218+
if token.requiresTrailingSpace {
219+
SwitchCase(label: SwitchCaseLabel(caseItems: [CaseItem(pattern: ExpressionPattern(expression: MemberAccessExpr(".\(token.swiftKind)")))])) {
220+
ReturnStmt("return true")
221+
}
222+
}
223+
}
224+
SwitchCase(label: SwitchCaseLabel(caseItems: [CaseItem(pattern: ExpressionPattern(expression: FunctionCallExpr(#".contextualKeyword("async")"#)))])) {
225+
ReturnStmt("return true")
226+
}
227+
SwitchCase(label: SwitchDefaultLabel()) {
228+
ReturnStmt("return false")
229+
}
230+
}
231+
}
232+
233+
FunctionDecl("""
234+
private func getKeyPath(_ node: Syntax) -> AnyKeyPath? {
235+
guard let parent = node.parent else {
236+
return nil
237+
}
238+
guard case .layout(let childrenKeyPaths) = type(of: parent.asProtocol(SyntaxProtocol.self)).structure else {
239+
return nil
240+
}
241+
return childrenKeyPaths[node.indexInParent]
242+
}
243+
"""
244+
)
40245
}
41246
}
42247

@@ -55,65 +260,6 @@ private func createChildVisitCall(childType: SyntaxBuildableType, rewrittenExpr:
55260
}
56261
}
57262

58-
private func makeLayoutNodeRewriteFunc(node: Node) -> FunctionDecl {
59-
let rewriteResultType: String
60-
if node.type.baseType?.syntaxKind == "Syntax" && node.type.syntaxKind != "Missing" {
61-
rewriteResultType = node.type.syntaxBaseName
62-
} else {
63-
rewriteResultType = node.type.baseType?.syntaxBaseName ?? node.type.syntaxBaseName
64-
}
65-
return FunctionDecl(
66-
leadingTrivia: .newline,
67-
modifiers: [DeclModifier(name: .open), DeclModifier(name: TokenSyntax.contextualKeyword("override", trailingTrivia: .space))],
68-
identifier: .identifier("visit"),
69-
signature: FunctionSignature(
70-
input: ParameterClause(parameterList: [
71-
FunctionParameter(
72-
firstName: Token.wildcard,
73-
secondName: .identifier("node"),
74-
colon: .colon,
75-
type: Type(node.type.syntaxBaseName)
76-
77-
)
78-
]),
79-
output: ReturnClause(returnType: Type(rewriteResultType))
80-
)
81-
) {
82-
for child in node.children {
83-
if child.isIndented {
84-
SequenceExpr("indentationLevel += 1")
85-
}
86-
let variableLetVar = child.requiresLeadingNewline ? "var" : "let"
87-
VariableDecl("\(variableLetVar) \(child.swiftName) = \(createChildVisitCall(childType: child.type, rewrittenExpr: MemberAccessExpr("node.\(child.swiftName)")))")
88-
if child.requiresLeadingNewline {
89-
IfStmt(
90-
"""
91-
if \(child.swiftName).leadingTrivia.first?.isNewline != true {
92-
\(child.swiftName).leadingTrivia = indentedNewline + \(child.swiftName).leadingTrivia
93-
}
94-
"""
95-
)
96-
}
97-
if child.isIndented {
98-
SequenceExpr("indentationLevel -= 1")
99-
}
100-
}
101-
let reconstructed = FunctionCallExpr(calledExpression: Expr("\(node.type.syntaxBaseName)")) {
102-
for child in node.children {
103-
TupleExprElement(
104-
label: child.isUnexpectedNodes ? nil : child.swiftName,
105-
expression: Expr(child.swiftName)
106-
)
107-
}
108-
}
109-
if rewriteResultType != node.type.syntaxBaseName {
110-
ReturnStmt("return \(rewriteResultType)(\(reconstructed))")
111-
} else {
112-
ReturnStmt("return \(reconstructed)")
113-
}
114-
}
115-
}
116-
117263
private func makeSyntaxCollectionRewriteFunc(node: Node) -> FunctionDecl {
118264
let rewriteResultType = node.type.syntaxBaseName
119265
return FunctionDecl(
@@ -157,84 +303,3 @@ private func makeSyntaxCollectionRewriteFunc(node: Node) -> FunctionDecl {
157303
ReturnStmt("return \(node.type.syntaxBaseName)(formattedChildren)")
158304
}
159305
}
160-
161-
private func createTokenFormatFunction() -> FunctionDecl {
162-
return FunctionDecl(
163-
leadingTrivia: .newline,
164-
modifiers: [DeclModifier(name: .open), DeclModifier(name: TokenSyntax.contextualKeyword("override", trailingTrivia: .space))],
165-
identifier: .identifier("visit"),
166-
signature: FunctionSignature(
167-
input: ParameterClause(parameterList: [
168-
FunctionParameter(
169-
firstName: Token.wildcard,
170-
secondName: .identifier("node"),
171-
colon: .colon,
172-
type: Type("TokenSyntax")
173-
174-
)
175-
]),
176-
output: ReturnClause(returnType: Type("TokenSyntax"))
177-
)
178-
) {
179-
VariableDecl("var leadingTrivia = node.leadingTrivia")
180-
VariableDecl("var trailingTrivia = node.trailingTrivia")
181-
SwitchStmt(expression: MemberAccessExpr(base: "node", name: "tokenKind")) {
182-
for token in SYNTAX_TOKENS where token.name != "ContextualKeyword" {
183-
SwitchCase(label: SwitchCaseLabel(caseItems: [CaseItem(pattern: ExpressionPattern(expression: MemberAccessExpr(name: token.swiftKind)))])) {
184-
if token.requiresLeadingSpace {
185-
IfStmt(
186-
"""
187-
if leadingTrivia.isEmpty && lastRewrittenToken?.trailingTrivia.isEmpty != false {
188-
leadingTrivia += .space
189-
}
190-
"""
191-
)
192-
}
193-
if token.requiresTrailingSpace {
194-
IfStmt(
195-
"""
196-
if trailingTrivia.isEmpty {
197-
trailingTrivia += .space
198-
}
199-
"""
200-
)
201-
}
202-
if !token.requiresLeadingSpace && !token.requiresTrailingSpace {
203-
BreakStmt("break")
204-
}
205-
}
206-
}
207-
SwitchCase(label: SwitchCaseLabel(caseItems: [CaseItem(pattern: ExpressionPattern(expression: MemberAccessExpr(name: "eof")))])) {
208-
BreakStmt("break")
209-
}
210-
SwitchCase(label: SwitchCaseLabel(caseItems: [CaseItem(pattern: ExpressionPattern(expression: MemberAccessExpr(name: "contextualKeyword")))])) {
211-
SwitchStmt(
212-
"""
213-
switch node.text {
214-
case "async":
215-
if trailingTrivia.isEmpty {
216-
trailingTrivia += .space
217-
}
218-
default:
219-
break
220-
}
221-
"""
222-
)
223-
}
224-
}
225-
SequenceExpr("leadingTrivia = leadingTrivia.indented(indentation: indentation)")
226-
SequenceExpr("trailingTrivia = trailingTrivia.indented(indentation: indentation)")
227-
VariableDecl(
228-
"""
229-
let rewritten = TokenSyntax(
230-
node.tokenKind,
231-
leadingTrivia: leadingTrivia,
232-
trailingTrivia: trailingTrivia,
233-
presence: node.presence
234-
)
235-
"""
236-
)
237-
SequenceExpr("lastRewrittenToken = rewritten")
238-
ReturnStmt("return rewritten")
239-
}
240-
}

0 commit comments

Comments
 (0)