|
| 1 | +//===----------------------------------------------------------------------===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2014 - 2022 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 Foundation |
| 14 | +import SwiftSyntax |
| 15 | +import SwiftSyntaxBuilder |
| 16 | +import SyntaxSupport |
| 17 | +import Utils |
| 18 | + |
| 19 | +let basicFormatFile = SourceFile { |
| 20 | + ImportDecl( |
| 21 | + leadingTrivia: .docLineComment(copyrightHeader), |
| 22 | + path: "SwiftSyntax" |
| 23 | + ) |
| 24 | + |
| 25 | + ClassDecl(modifiers: [Token.open], identifier: "BasicFormat", inheritanceClause: TypeInheritanceClause { InheritedType(typeName: "SyntaxRewriter") }) { |
| 26 | + VariableDecl("public var indentationLevel: Int = 0") |
| 27 | + VariableDecl("open var indentation: TriviaPiece { .spaces(indentationLevel * 4) }") |
| 28 | + VariableDecl("private var indentedNewline: Trivia { Trivia(pieces: [.newlines(1), indentation]) }") |
| 29 | + VariableDecl("private var lastRewrittenToken: TokenSyntax?") |
| 30 | + |
| 31 | + for node in SYNTAX_NODES where !node.isBase { |
| 32 | + if node.isSyntaxCollection { |
| 33 | + makeSyntaxCollectionRewriteFunc(node: node) |
| 34 | + } else { |
| 35 | + makeLayoutNodeRewriteFunc(node: node) |
| 36 | + } |
| 37 | + } |
| 38 | + |
| 39 | + createTokenFormatFunction() |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | +private func makeLayoutNodeRewriteFunc(node: Node) -> FunctionDecl { |
| 44 | + let rewriteResultType: String |
| 45 | + if node.isSyntaxCollection { |
| 46 | + rewriteResultType = "Syntax" |
| 47 | + } else { |
| 48 | + rewriteResultType = node.type.baseType?.syntaxBaseName ?? "Syntax" |
| 49 | + } |
| 50 | + return FunctionDecl( |
| 51 | + leadingTrivia: .newline, |
| 52 | + modifiers: [Token.open, Token(tokenSyntax: TokenSyntax.contextualKeyword("override", trailingTrivia: .space))], |
| 53 | + identifier: .identifier("visit"), |
| 54 | + signature: FunctionSignature( |
| 55 | + input: ParameterClause(parameterList: [ |
| 56 | + FunctionParameter( |
| 57 | + firstName: Token.wildcard, |
| 58 | + secondName: .identifier("node"), |
| 59 | + colon: .colon, |
| 60 | + type: node.type.syntaxBaseName |
| 61 | + |
| 62 | + ) |
| 63 | + ]), |
| 64 | + output: rewriteResultType |
| 65 | + ) |
| 66 | + ) { |
| 67 | + for child in node.children { |
| 68 | + if child.isIndented { |
| 69 | + SequenceExpr("indentationLevel += 1") |
| 70 | + } |
| 71 | + let variableLetVar = child.requiresLeadingNewline ? "var" : "let" |
| 72 | + if child.isOptional { |
| 73 | + VariableDecl("\(variableLetVar) \(child.swiftName) = node.\(child.swiftName).map(self.visit)?.cast(\(child.type.syntaxBaseName).self)") |
| 74 | + } else { |
| 75 | + VariableDecl("\(variableLetVar) \(child.swiftName) = self.visit(node.\(child.swiftName)).cast(\(child.type.syntaxBaseName).self)") |
| 76 | + } |
| 77 | + if child.requiresLeadingNewline { |
| 78 | + IfStmt( |
| 79 | + """ |
| 80 | + if \(child.swiftName).leadingTrivia.first?.isNewline != true { |
| 81 | + \(child.swiftName).leadingTrivia = indentedNewline + \(child.swiftName).leadingTrivia |
| 82 | + } |
| 83 | + """ |
| 84 | + ) |
| 85 | + } |
| 86 | + if child.isIndented { |
| 87 | + SequenceExpr("indentationLevel -= 1") |
| 88 | + } |
| 89 | + } |
| 90 | + let reconstructed = FunctionCallExpr(calledExpression: "\(node.type.syntaxBaseName)") { |
| 91 | + for child in node.children { |
| 92 | + TupleExprElement( |
| 93 | + label: child.isUnexpectedNodes ? nil : child.swiftName, |
| 94 | + expression: child.swiftName |
| 95 | + ) |
| 96 | + } |
| 97 | + } |
| 98 | + ReturnStmt("return \(rewriteResultType)(\(reconstructed))") |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +private func makeSyntaxCollectionRewriteFunc(node: Node) -> FunctionDecl { |
| 103 | + let rewriteResultType: String |
| 104 | + if node.isSyntaxCollection { |
| 105 | + rewriteResultType = "Syntax" |
| 106 | + } else { |
| 107 | + rewriteResultType = node.type.baseType?.syntaxBaseName ?? "Syntax" |
| 108 | + } |
| 109 | + return FunctionDecl( |
| 110 | + leadingTrivia: .newline, |
| 111 | + modifiers: [Token.open, Token(tokenSyntax: TokenSyntax.contextualKeyword("override", trailingTrivia: .space))], |
| 112 | + identifier: .identifier("visit"), |
| 113 | + signature: FunctionSignature( |
| 114 | + input: ParameterClause(parameterList: [ |
| 115 | + FunctionParameter( |
| 116 | + firstName: Token.wildcard, |
| 117 | + secondName: .identifier("node"), |
| 118 | + colon: .colon, |
| 119 | + type: node.type.syntaxBaseName |
| 120 | + |
| 121 | + ) |
| 122 | + ]), |
| 123 | + output: rewriteResultType |
| 124 | + ) |
| 125 | + ) { |
| 126 | + let formattedChildrenVarLet = node.elementsSeparatedByNewline ? "var" : "let" |
| 127 | + VariableDecl( |
| 128 | + """ |
| 129 | + \(formattedChildrenVarLet) formattedChildren = node.children(viewMode: .all).map { |
| 130 | + self.visit($0).cast(\(node.collectionElementType.syntaxBaseName).self) |
| 131 | + } |
| 132 | + """ |
| 133 | + ) |
| 134 | + if node.elementsSeparatedByNewline { |
| 135 | + SequenceExpr( |
| 136 | + """ |
| 137 | + formattedChildren = formattedChildren.map { |
| 138 | + if $0.leadingTrivia?.first?.isNewline == true { |
| 139 | + return $0 |
| 140 | + } else { |
| 141 | + return $0.withLeadingTrivia(indentedNewline + ($0.leadingTrivia ?? [])) |
| 142 | + } |
| 143 | + } |
| 144 | + """ |
| 145 | + ) |
| 146 | + } |
| 147 | + ReturnStmt("return Syntax(\(node.type.syntaxBaseName)(formattedChildren))") |
| 148 | + } |
| 149 | +} |
| 150 | + |
| 151 | +private func createTokenFormatFunction() -> FunctionDecl { |
| 152 | + return FunctionDecl( |
| 153 | + leadingTrivia: .newline, |
| 154 | + modifiers: [Token.open, Token(tokenSyntax: TokenSyntax.contextualKeyword("override", trailingTrivia: .space))], |
| 155 | + identifier: .identifier("visit"), |
| 156 | + signature: FunctionSignature( |
| 157 | + input: ParameterClause(parameterList: [ |
| 158 | + FunctionParameter( |
| 159 | + firstName: Token.wildcard, |
| 160 | + secondName: .identifier("node"), |
| 161 | + colon: .colon, |
| 162 | + type: "TokenSyntax" |
| 163 | + |
| 164 | + ) |
| 165 | + ]), |
| 166 | + output: "Syntax" |
| 167 | + ) |
| 168 | + ) { |
| 169 | + VariableDecl("var node = node") |
| 170 | + SwitchStmt(expression: MemberAccessExpr(base: "node", name: "tokenKind")) { |
| 171 | + for token in SYNTAX_TOKENS { |
| 172 | + SwitchCase(label: SwitchCaseLabel(caseItems: CaseItem(pattern: ExpressionPattern(expression: MemberAccessExpr(name: token.swiftKind))))) { |
| 173 | + if token.requiresLeadingSpace { |
| 174 | + IfStmt( |
| 175 | + """ |
| 176 | + if node.leadingTrivia.isEmpty && lastRewrittenToken?.trailingTrivia.isEmpty != false { |
| 177 | + node.leadingTrivia += .space |
| 178 | + } |
| 179 | + """ |
| 180 | + ) |
| 181 | + } |
| 182 | + if token.requiresTrailingSpace { |
| 183 | + IfStmt( |
| 184 | + """ |
| 185 | + if node.trailingTrivia.isEmpty { |
| 186 | + node.trailingTrivia += .space |
| 187 | + } |
| 188 | + """ |
| 189 | + ) |
| 190 | + } |
| 191 | + if !token.requiresLeadingSpace && !token.requiresTrailingSpace { |
| 192 | + BreakStmt("break") |
| 193 | + } |
| 194 | + } |
| 195 | + } |
| 196 | + SwitchCase(label: SwitchCaseLabel(caseItems: CaseItem(pattern: ExpressionPattern(expression: MemberAccessExpr(name: "eof"))))) { |
| 197 | + BreakStmt("break") |
| 198 | + } |
| 199 | + } |
| 200 | + SequenceExpr("node.leadingTrivia = node.leadingTrivia.indented(indentation: indentation)") |
| 201 | + SequenceExpr("node.trailingTrivia = node.trailingTrivia.indented(indentation: indentation)") |
| 202 | + SequenceExpr("lastRewrittenToken = node") |
| 203 | + ReturnStmt("return Syntax(node)") |
| 204 | + } |
| 205 | +} |
0 commit comments