Skip to content

Commit

Permalink
Unify functions for generating ExpressibleAs conformances
Browse files Browse the repository at this point in the history
  • Loading branch information
fwcd committed Aug 4, 2022
1 parent 2caa68e commit 57b91b1
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 65 deletions.
27 changes: 27 additions & 0 deletions Sources/SwiftSyntaxBuilderGeneration/SyntaxUtilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,30 @@ func createFormatLeadingTriviaParameters(withDefaultTrivia: Bool = false) -> Par
]
)
}

/// Generate the `create...` function for an `ExpressibleAs...` conformance.
func createExpressibleAsCreateFunction(type: SyntaxBuildableType, additionalDocComments: [String] = []) -> FunctionDecl {
FunctionDecl(
leadingTrivia: ([
"/// Conformance to `\(type.expressibleAsBaseName)`.",
] + additionalDocComments).map { .docLineComment($0) + .newline }.reduce([], +),
modifiers: [TokenSyntax.public],
identifier: .identifier("create\(type.buildableBaseName)"),
signature: FunctionSignature(
input: ParameterClause(),
output: type.buildable
)
) {
ReturnStmt(expression: "self")
}
}

/// Generate the `create...` function for an `ExpressibleAs...` conformance
/// that includes an explanation as to how the function disambiguates a conformance.
func createDisambiguatingExpressibleAsCreateFunction(type: SyntaxBuildableType, baseType: SyntaxBuildableType) -> FunctionDecl {
createExpressibleAsCreateFunction(type: baseType, additionalDocComments: [
"/// `\(type.buildableBaseName)` may conform to `\(baseType.expressibleAsBaseName)` via different `ExpressibleAs*` paths.",
"/// Thus, there are multiple default implementations of `create\(baseType.buildableBaseName)`, some of which perform conversions",
"/// through `ExpressibleAs*` protocols. To resolve the ambiguity, provie a fixed implementation that doesn't perform any conversions.",
])
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ let buildableCollectionNodesFile = SourceFile {
// Generate function declarations
createBuildFunction(node: node)
createBuildSyntaxFunction(node: node)
createExpressibleAsCreateFunction(node: node)
createSyntaxBuildableCreateFunction(node: node)
createExpressibleAsCreateFunction(type: type)
createDisambiguatingExpressibleAsCreateFunction(type: type, baseType: .init(syntaxKind: "Syntax"))
}

// For nodes without expressible-as conformances, conform Array to the corresponding expressible-as
Expand Down Expand Up @@ -258,39 +258,3 @@ private func createBuildSyntaxFunction(node: Node) -> FunctionDecl {
})
}
}

/// Generate the `create...` function for the `ExpressibleAs...` conformance.
private func createExpressibleAsCreateFunction(node: Node) -> FunctionDecl {
let type = node.type
return FunctionDecl(
leadingTrivia: .docLineComment("/// Conformance to `\(type.expressibleAsBaseName)`") + .newline,
modifiers: [TokenSyntax.public],
identifier: .identifier("create\(type.buildableBaseName)"),
signature: FunctionSignature(
input: ParameterClause(),
output: type.buildable
)
) {
ReturnStmt(expression: "self")
}
}

/// Generate the `createSyntaxBuildable` function for the `SyntaxBuildable` conformance.
private func createSyntaxBuildableCreateFunction(node: Node) -> FunctionDecl {
let type = node.type
return FunctionDecl(
leadingTrivia: [
"/// `\(type.buildableBaseName)` might conform to `SyntaxBuildable` via different `ExpressibleAs*` paths.",
"/// Thus, there are multiple default implementations for `createSyntaxBuildable`, some of which perform conversions through `ExpressibleAs*` protocols.",
"/// To resolve the ambiguity, provide a fixed implementation that doesn't perform any conversions.",
].map { .docLineComment($0) + .newline }.reduce([], +),
modifiers: [TokenSyntax.public],
identifier: .identifier("createSyntaxBuildable"),
signature: FunctionSignature(
input: ParameterClause(),
output: "SyntaxBuildable"
)
) {
ReturnStmt(expression: "self")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -332,33 +332,6 @@ private func createFormatAdditionalLeadingTriviaParams() -> ParameterClause {
}
}

/// Generate the `create...` function for an `ExpressibleAs...` conformance.
private func createExpressibleAsCreateFunction(type: SyntaxBuildableType, additionalDocComments: [String] = []) -> FunctionDecl {
FunctionDecl(
leadingTrivia: ([
"/// Conformance to `\(type.expressibleAsBaseName)`.",
] + additionalDocComments).map { .docLineComment($0) + .newline }.reduce([], +),
modifiers: [TokenSyntax.public],
identifier: .identifier("create\(type.buildableBaseName)"),
signature: FunctionSignature(
input: ParameterClause(),
output: type.buildable
)
) {
ReturnStmt(expression: "self")
}
}

/// Generate the `create...` function for an `ExpressibleAs...` conformance
/// that includes an explanation as to how the function disambiguates a conformance.
private func createDisambiguatingExpressibleAsCreateFunction(type: SyntaxBuildableType, baseType: SyntaxBuildableType) -> FunctionDecl {
createExpressibleAsCreateFunction(type: baseType, additionalDocComments: [
"/// `\(type.buildableBaseName)` may conform to `\(baseType.expressibleAsBaseName)` via different `ExpressibleAs*` paths.",
"/// Thus, there are multiple default implementations of `create\(baseType.buildableBaseName)`, some of which perform conversions",
"/// through `ExpressibleAs*` protocols. To resolve the ambiguity, provie a fixed implementation that doesn't perform any conversions.",
])
}

/// Generate the `withTrailingComma` function.
private func createWithTrailingCommaFunction(node: Node) -> FunctionDecl {
let children = node.children
Expand Down

0 comments on commit 57b91b1

Please sign in to comment.