Description
Description
Currently a SubscriptDeclSyntax
can only be initialized using a string or the different parts that make it up. Adding the capability for result builders to create accessors would greatly increase the ease of use in generating subscripts. It would be ideal for the result builders to support both the shortened syntax that only provides a getter and the longer syntax providing the ability to declare multiple accessors. Similar to the issue I just opened with the VariableDeclSyntax
type not having the ability to declare multiple accessors using result builders (issue #2948), this extension could also use a private shared initializer incorporating the work done by both types and then each specific implementation incorporating the differences specific to that kind of result builder.
Comparison Between Current and Proposed methods
Note that after this change, the existing methods to create subscripts will still be supported. Also, all modifications of this code is to go into the SwiftSyntaxBuilder target since it deals with the result builders. The following usage of the currently available API assumes that SwiftSyntax and SwiftSyntaxBuilder are both imported.
Protocol Requirements
Protocol requirements aren't affected by this change since they have no body. In these cases, continuing to use the SwiftSyntaxBuilder SubscriptDeclSyntax(_:)
is sufficient. See the example below:
try! SubscriptDeclSyntax("subscript(_ index: Index) -> Element")
Single Accessor
This code:
SubscriptDeclSyntax(parameterClause: FunctionParameterClauseSyntax(parametersBuilder: {
"_ index: Index"
}),
returnClause: ReturnClauseSyntax(arrow: .arrowToken(leadingTrivia: .space, trailingTrivia: .space), type: TypeSyntax("Element")),
accessorBlock: .getter(CodeBlockItemSyntax {
// code in getter, represented as SwiftSyntax types
})
)
is currently required to generate (the lack of tabs is currently due to it appearing that there isn't a way to tabulate code in GitHub markdown):
subscript(_ index: Index) -> Element {
// code in getter
}
Using result builders, the above code can be simplified to:
try! SubscriptDeclSyntax("subscript(_ index: Index) -> Element") {
// code in getter represented as SwiftSyntax types
}
Multiple Accessors
Similarly we can apply the above code with an additional set accessor generated using the currently available API:
SubscriptDeclSyntax(parameterClause: FunctionParameterClauseSyntax(parametersBuilder: {
"_ index: Index"
}),
returnClause: ReturnClauseSyntax(arrow: .arrowToken(leadingTrivia: .space, trailingTrivia: .space), type: TypeSyntax("Element")),
accessorBlock: .accessors(AccessorDeclListSyntax {
try! AccessorDeclSyntax("get") {
// code in getter represented as SwiftSyntax types
}
try! AccessorDeclSyntax("set") {
// code in setter represented as SwiftSyntax types
}
})
)
which generates:
subscript(_ index: Index) -> Element {
get {
// code in getter
}
set {
// code in setter
}
}
and would be expressible as the following if this feature is adopted:
SubscriptDeclSyntax("subscript(_ index: Index) -> Element") {
try! AccessorDeclSyntax("get") {
// code in getter represented as SwiftSyntax types
}
try! AccessorDeclSyntax("set") {
// code in setter represented as SwiftSyntax types
}
}
Declarations
The method headers that would be added would likely be similar to:
// single getter
public init(_ header: SyntaxNodeString, @CodeBlockItemListBuilder accessor: () throws -> CodeBlockItemListSyntax) throws {
try self.init(header, accessorBlock: .getter(accessor()))
}
// multiple accessors
public init(_ header: SyntaxNodeString, @AccessorDeclListBuilder accessors: () throws -> AccessorDeclListSyntax) throws {
try self.init(header, accessorBlock: .accessors(accessors()))
}
// shared initializer doing any required work that would be common to both of the above public methods, receiving the formatted accessor from the appropriate public method declared above.
private init(_ header: SyntaxNodeString, accessorBlock: AccessorBlockSyntax) throws