Skip to content

Update CodeGeneration to use new convenience initializers #1019

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CodeGeneration/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let package = Package(
.executable(name: "generate-swiftsyntaxbuilder", targets: ["generate-swiftsyntaxbuilder"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-syntax.git", revision: "fa7ff05591294db031e3061e704994aa3b89d1bc"),
.package(url: "https://github.com/apple/swift-syntax.git", revision: "5e9dcce1dc5c81e48b658ced23f0848be4671a0c"),
.package(url: "https://github.com/apple/swift-argument-parser.git", .upToNextMinor(from: "1.1.4")),
],
targets: [
Expand Down
2 changes: 1 addition & 1 deletion CodeGeneration/Sources/Utils/SyntaxBuildableChild.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public extension Child {
}))
}
let disjunction = ExprList(assertChoices.flatMap { [$0, Expr(BinaryOperatorExpr(text: "||"))] }.dropLast())
return FunctionCallExpr(calledExpression: Expr("assert")) {
return FunctionCallExpr(callee: "assert") {
TupleExprElement(expression: SequenceExpr(elements: disjunction))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,23 +62,10 @@ private func makeLayoutNodeRewriteFunc(node: Node) -> FunctionDecl {
} else {
rewriteResultType = node.type.baseType?.syntaxBaseName ?? node.type.syntaxBaseName
}
return FunctionDecl(
leadingTrivia: .newline,
modifiers: [DeclModifier(name: .open), DeclModifier(name: TokenSyntax.contextualKeyword("override", trailingTrivia: .space))],
identifier: .identifier("visit"),
signature: FunctionSignature(
input: ParameterClause(parameterList: [
FunctionParameter(
firstName: Token.wildcard,
secondName: .identifier("node"),
colon: .colon,
type: Type(node.type.syntaxBaseName)
return FunctionDecl("""

)
]),
output: ReturnClause(returnType: Type(rewriteResultType))
)
) {
open override func visit(_ node: \(node.type.syntaxBaseName)) -> \(rewriteResultType)
""") {
for child in node.children {
if child.isIndented {
SequenceExpr("indentationLevel += 1")
Expand All @@ -98,7 +85,7 @@ private func makeLayoutNodeRewriteFunc(node: Node) -> FunctionDecl {
SequenceExpr("indentationLevel -= 1")
}
}
let reconstructed = FunctionCallExpr(calledExpression: Expr("\(node.type.syntaxBaseName)")) {
let reconstructed = FunctionCallExpr(callee: node.type.syntaxBaseName) {
for child in node.children {
TupleExprElement(
label: child.isUnexpectedNodes ? nil : child.swiftName,
Expand All @@ -116,23 +103,10 @@ private func makeLayoutNodeRewriteFunc(node: Node) -> FunctionDecl {

private func makeSyntaxCollectionRewriteFunc(node: Node) -> FunctionDecl {
let rewriteResultType = node.type.syntaxBaseName
return FunctionDecl(
leadingTrivia: .newline,
modifiers: [DeclModifier(name: .open), DeclModifier(name: TokenSyntax.contextualKeyword("override", trailingTrivia: .space))],
identifier: .identifier("visit"),
signature: FunctionSignature(
input: ParameterClause(parameterList: [
FunctionParameter(
firstName: Token.wildcard,
secondName: .identifier("node"),
colon: .colon,
type: Type(node.type.syntaxBaseName)
return FunctionDecl("""

)
]),
output: ReturnClause(returnType: Type(rewriteResultType))
)
) {
open override func visit(_ node: \(node.type.syntaxBaseName)) -> \(rewriteResultType)
""") {
let formattedChildrenVarLet = node.elementsSeparatedByNewline ? "var" : "let"
VariableDecl(
"""
Expand All @@ -159,28 +133,15 @@ private func makeSyntaxCollectionRewriteFunc(node: Node) -> FunctionDecl {
}

private func createTokenFormatFunction() -> FunctionDecl {
return FunctionDecl(
leadingTrivia: .newline,
modifiers: [DeclModifier(name: .open), DeclModifier(name: TokenSyntax.contextualKeyword("override", trailingTrivia: .space))],
identifier: .identifier("visit"),
signature: FunctionSignature(
input: ParameterClause(parameterList: [
FunctionParameter(
firstName: Token.wildcard,
secondName: .identifier("node"),
colon: .colon,
type: Type("TokenSyntax")
return FunctionDecl("""

)
]),
output: ReturnClause(returnType: Type("TokenSyntax"))
)
) {
open override func visit(_ node: TokenSyntax) -> TokenSyntax
""") {
VariableDecl("var leadingTrivia = node.leadingTrivia")
VariableDecl("var trailingTrivia = node.trailingTrivia")
SwitchStmt(expression: MemberAccessExpr(base: "node", name: "tokenKind")) {
for token in SYNTAX_TOKENS where token.name != "ContextualKeyword" {
SwitchCase(label: SwitchCaseLabel(caseItems: [CaseItem(pattern: ExpressionPattern(expression: MemberAccessExpr(name: token.swiftKind)))])) {
SwitchCase("case .\(token.swiftKind):") {
if token.requiresLeadingSpace {
IfStmt(
"""
Expand All @@ -204,10 +165,10 @@ private func createTokenFormatFunction() -> FunctionDecl {
}
}
}
SwitchCase(label: SwitchCaseLabel(caseItems: [CaseItem(pattern: ExpressionPattern(expression: MemberAccessExpr(name: "eof")))])) {
SwitchCase("case .eof:") {
BreakStmt("break")
}
SwitchCase(label: SwitchCaseLabel(caseItems: [CaseItem(pattern: ExpressionPattern(expression: MemberAccessExpr(name: "contextualKeyword")))])) {
SwitchCase("case .contextualKeyword:") {
SwitchStmt(
"""
switch node.text {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,9 @@ let buildableCollectionNodesFile = SourceFile {
for node in SYNTAX_NODES where node.isSyntaxCollection {
let elementType = node.collectionElementType

let docComment = node.documentation.isEmpty ? "" : "/// \(node.documentation)\n"
// Generate collection node struct
ExtensionDecl(
leadingTrivia: node.documentation.isEmpty
? []
: .docLineComment("/// \(node.documentation)") + .newline,
extendedType: Type(node.type.shorthandName),
inheritanceClause: TypeInheritanceClause { InheritedType(typeName: Type("ExpressibleByArrayLiteral")) }
) {
ExtensionDecl("\(docComment)extension \(node.type.shorthandName): ExpressibleByArrayLiteral") {
// Generate initializers
if elementType.isBaseType && node.collectionElementChoices?.isEmpty ?? true {
InitializerDecl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,9 @@ let buildableNodesFile = SourceFile {
let type = node.type
let hasTrailingComma = node.traits.contains("WithTrailingComma")

// Generate node struct
let docComment: SwiftSyntax.Trivia = node.documentation.isEmpty ? [] : .docLineComment("/// \(node.documentation)") + .newline
ExtensionDecl(
leadingTrivia: node.documentation.isEmpty
? []
: .docLineComment("/// \(node.documentation)") + .newline,
leadingTrivia: docComment,
extendedType: Type(type.shorthandName),
inheritanceClause: hasTrailingComma ? TypeInheritanceClause { InheritedType(typeName: Type("HasTrailingComma")) } : nil
) {
Expand Down Expand Up @@ -89,12 +87,7 @@ private func createDefaultInitializer(node: Node) -> InitializerDecl {
signature: FunctionSignature(
input: ParameterClause {
for trivia in ["leadingTrivia", "trailingTrivia"] {
FunctionParameter(
firstName: .identifier(trivia),
colon: .colon,
type: Type("Trivia"),
defaultArgument: InitializerClause(value: ArrayExpr())
)
FunctionParameter("\(trivia): Trivia = []", for: .functionParameters)
}
for child in node.children {
FunctionParameter(
Expand All @@ -112,7 +105,7 @@ private func createDefaultInitializer(node: Node) -> InitializerDecl {
assertStmt
}
}
let nodeConstructorCall = FunctionCallExpr(calledExpression: Expr(type.syntaxBaseName)) {
let nodeConstructorCall = FunctionCallExpr(callee: type.syntaxBaseName) {
for child in node.children {
TupleExprElement(
label: child.isUnexpectedNodes ? nil : child.swiftName,
Expand Down Expand Up @@ -156,21 +149,16 @@ private func createConvenienceInitializer(node: Node) -> InitializerDecl? {
} else {
produceExpr = Expr(FunctionCallExpr("\(child.swiftName)Builder()"))
}
let defaultArgument = ClosureExpr {
if child.type.isOptional {
NilLiteralExpr()
} else {
FunctionCallExpr("\(builderInitializableType.syntax)([])")
}
}
builderParameters.append(FunctionParameter(
attributes: [CustomAttribute(attributeName: Type(builderInitializableType.resultBuilderBaseName), argumentList: nil)],
firstName: .identifier("\(child.swiftName)Builder").withLeadingTrivia(.space),
colon: .colon,
type: FunctionType(
arguments: [],
returnType: builderInitializableType.syntax
),
defaultArgument: InitializerClause(value: ClosureExpr {
if child.type.isOptional {
NilLiteralExpr()
} else {
FunctionCallExpr("\(builderInitializableType.syntax)([])")
}
})
"@\(builderInitializableType.resultBuilderBaseName) \(child.swiftName)Builder: () -> \(builderInitializableType.syntax) = \(defaultArgument)",
for: .functionParameters
))
} else if let token = child.type.token, token.text == nil {
// Allow initializing identifiers and other tokens without default text with a String
Expand All @@ -182,11 +170,7 @@ private func createConvenienceInitializer(node: Node) -> InitializerDecl? {
} else {
produceExpr = Expr(FunctionCallExpr("\(tokenExpr)(\(child.swiftName))"))
}
normalParameters.append(FunctionParameter(
firstName: .identifier(child.swiftName),
colon: .colon,
type: paramType
))
normalParameters.append(FunctionParameter("\(child.swiftName): \(paramType)", for: .functionParameters))
} else {
produceExpr = convertFromSyntaxProtocolToSyntaxType(child: child)
normalParameters.append(FunctionParameter(
Expand Down Expand Up @@ -217,19 +201,14 @@ private func createConvenienceInitializer(node: Node) -> InitializerDecl? {
modifiers: [DeclModifier(name: .public)],
signature: FunctionSignature(
input: ParameterClause {
FunctionParameter(
firstName: .identifier("leadingTrivia"),
colon: .colon,
type: Type("Trivia"),
defaultArgument: InitializerClause(value: ArrayExpr())
)
FunctionParameter("leadingTrivia: Trivia = []", for: .functionParameters)
for param in normalParameters + builderParameters {
param
}
}
)
) {
FunctionCallExpr(calledExpression: MemberAccessExpr("self.init")) {
FunctionCallExpr(callee: "self.init") {
for arg in delegatedInitArgs {
arg
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@ let resultBuildersFile = SourceFile {
let elementType = node.collectionElementType
let expressionType: Type = (node.collectionElementChoices?.isEmpty ?? true) ? elementType.parameterType : Type(MemberTypeIdentifier("\(type.buildable).Element"))

StructDecl(
attributes: [CustomAttribute(trailingTrivia: .newline, attributeName: Type("resultBuilder"))],
modifiers: [DeclModifier(name: .public)],
identifier: "\(type.syntaxKind)Builder") {

TypealiasDecl(
StructDecl("""
@resultBuilder
public struct \(type.syntaxKind)Builder
""") {
TypealiasDecl(
"""
/// The type of individual statement expressions in the transformed function,
/// which defaults to Component if buildExpression() is not provided.
Expand Down Expand Up @@ -146,38 +145,26 @@ let resultBuildersFile = SourceFile {
"""
)

FunctionDecl(
leadingTrivia: [
.newlines(1),
.docLineComment("/// If declared, this will be called on the partial result from the outermost"),
.newlines(1),
.docLineComment("/// block statement to produce the final returned result."),
.newlines(1)],
modifiers: [DeclModifier(name: .public), DeclModifier(name: .static)],
identifier: .identifier("buildFinalResult"),
signature: FunctionSignature(
input: ParameterClause {
FunctionParameter(
firstName: .wildcard,
secondName: .identifier("component"),
colon: .colon,
type: Type("Component"))
},
output: ReturnClause(returnType: Type("FinalResult")))) {
if elementType.isToken {
ReturnStmt("return .init(component)")
} else if elementType.hasWithTrailingCommaTrait {
VariableDecl("let lastIndex = component.count - 1")
FunctionDecl("""

/// If declared, this will be called on the partial result from the outermost
/// block statement to produce the final returned result.
public static func buildFinalResult(_ component: Component) -> FinalResult
""") {
if elementType.isToken {
ReturnStmt("return .init(component)")
} else if elementType.hasWithTrailingCommaTrait {
VariableDecl("let lastIndex = component.count - 1")

ReturnStmt("""
return .init(component.enumerated().map { index, source in
return index < lastIndex ? source.ensuringTrailingComma() : source
})
""")
} else {
ReturnStmt("return .init(component)")
}
}
ReturnStmt("""
return .init(component.enumerated().map { index, source in
return index < lastIndex ? source.ensuringTrailingComma() : source
})
""")
} else {
ReturnStmt("return .init(component)")
}
}
}

ExtensionDecl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ let tokenFile = SourceFile {
path: [AccessPathComponent(name: "SwiftSyntax")]
)

ExtensionDecl(modifiers: [DeclModifier(name: .public)], extendedType: Type("TokenSyntax")) {
ExtensionDecl("public extension TokenSyntax") {
for token in SYNTAX_TOKENS {
if token.isKeyword {
VariableDecl("""
Expand Down