Skip to content

Don’t automaticaly conform all decl/stmt/etc. nodes to ExpressibleByStringLiteral #1269

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
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
Original file line number Diff line number Diff line change
Expand Up @@ -35,38 +35,8 @@ let syntaxExpressibleByStringInterpolationConformancesFile = SourceFileSyntax {
""")
}

for node in SYNTAX_NODES {
if node.isBase {
ExtensionDeclSyntax("extension \(raw: node.name)Protocol") {
InitializerDeclSyntax(
"""
public init(stringInterpolationOrThrow stringInterpolation: SyntaxStringInterpolation) throws {
self = try performParse(source: stringInterpolation.sourceText, parse: { parser in
let node = \(raw: node.name).parse(from: &parser)
guard let result = node.as(Self.self) else {
throw SyntaxStringInterpolationError.producedInvalidNodeType(expectedType: Self.self, actualType: node.kind.syntaxNodeType)
}
return result
})
}
""")
}
}

if node.parserFunction != nil {
ExtensionDeclSyntax("extension \(raw: node.name): SyntaxExpressibleByStringInterpolation") {
InitializerDeclSyntax(
"""
public init(stringInterpolationOrThrow stringInterpolation: SyntaxStringInterpolation) throws {
self = try performParse(source: stringInterpolation.sourceText, parse: { parser in
return Self.parse(from: &parser)
})
}
""")
}
} else if !node.isMissing && node.baseType.baseName != "Syntax" && node.baseType.baseName != "SyntaxCollection" {
ExtensionDeclSyntax("extension \(raw: node.name): SyntaxExpressibleByStringInterpolation { }")
}
for node in SYNTAX_NODES where node.parserFunction != nil {
ExtensionDeclSyntax("extension \(raw: node.name): SyntaxExpressibleByStringInterpolation {}")
}

FunctionDeclSyntax(
Expand Down
4 changes: 2 additions & 2 deletions Examples/CodeGenerationUsingSwiftSyntaxBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ struct Main {
let source = SourceFileSyntax {
StructDeclSyntax(identifier: "Person") {
for (propertyName, propertyType) in properties {
VariableDeclSyntax("var \(raw: propertyName): \(raw: propertyType)")
DeclSyntax("var \(raw: propertyName): \(raw: propertyType)")

FunctionDeclSyntax("""
DeclSyntax("""
func with\(raw: propertyName.withFirstLetterUppercased())(_ \(raw: propertyName): \(raw: propertyType)) -> Person {
var result = self
result.\(raw: propertyName) = \(raw: propertyName)
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftSyntaxBuilder/ConvenienceInitializers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ extension VariableDeclSyntax {
attributes: AttributeListSyntax? = nil,
modifiers: ModifierListSyntax? = nil,
_ letOrVarKeyword: Keyword,
name: IdentifierPatternSyntax,
name: PatternSyntax,
type: TypeAnnotationSyntax? = nil,
initializer: InitializerClauseSyntax? = nil
) {
Expand All @@ -431,7 +431,7 @@ extension VariableDeclSyntax {
leadingTrivia: Trivia = [],
attributes: AttributeListSyntax? = nil,
modifiers: ModifierListSyntax? = nil,
name: IdentifierPatternSyntax,
name: PatternSyntax,
type: TypeAnnotationSyntax,
@CodeBlockItemListBuilder accessor: () -> CodeBlockItemListSyntax
) {
Expand Down
4 changes: 4 additions & 0 deletions Sources/SwiftSyntaxBuilder/Syntax+StringInterpolation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ enum SyntaxStringInterpolationError: Error, CustomStringConvertible {
case producedInvalidNodeType(expectedType: SyntaxProtocol.Type, actualType: SyntaxProtocol.Type)
case diagnostics([Diagnostic], tree: Syntax)

static func producedInvalidNodeType<S: SyntaxProtocol>(expectedType: SyntaxProtocol.Type, actualNode: S) -> Self {
return .producedInvalidNodeType(expectedType: expectedType, actualType: type(of: actualNode))
}

var description: String {
switch self {
case .producedInvalidNodeType(expectedType: let expectedType, actualType: let actualType):
Expand Down
75 changes: 57 additions & 18 deletions Sources/SwiftSyntaxBuilder/SyntaxNodeWithBody.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,27 @@ extension SyntaxStringInterpolation {

public protocol HasTrailingCodeBlock {
var body: CodeBlockSyntax { get set }

init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () -> CodeBlockItemListSyntax) throws
}

public extension HasTrailingCodeBlock where Self: SyntaxExpressibleByStringInterpolation {
init(_ signature: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () -> CodeBlockItemListSyntax) {
self = "\(signature) {}"
public extension HasTrailingCodeBlock where Self: StmtSyntaxProtocol {
init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () -> CodeBlockItemListSyntax) throws {
let stmt = StmtSyntax("\(header) {}")
guard let castedStmt = stmt.as(Self.self) else {
throw SyntaxStringInterpolationError.producedInvalidNodeType(expectedType: Self.self, actualNode: stmt)
}
self = castedStmt
self.body = CodeBlockSyntax(statements: bodyBuilder())
}
}

extension CatchClauseSyntax: HasTrailingCodeBlock {}
extension CatchClauseSyntax: HasTrailingCodeBlock {
public init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () -> CodeBlockItemListSyntax) throws {
self = CatchClauseSyntax("\(header) {}")
self.body = CodeBlockSyntax(statements: bodyBuilder())
}
}
extension DeferStmtSyntax: HasTrailingCodeBlock {}
extension DoStmtSyntax: HasTrailingCodeBlock {}
extension ForInStmtSyntax: HasTrailingCodeBlock {}
Expand All @@ -59,11 +70,17 @@ extension WhileStmtSyntax: HasTrailingCodeBlock {}

public protocol HasTrailingOptionalCodeBlock {
var body: CodeBlockSyntax? { get set }

init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () -> CodeBlockItemListSyntax) throws
}

public extension HasTrailingOptionalCodeBlock where Self: SyntaxExpressibleByStringInterpolation {
init(_ signature: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () -> CodeBlockItemListSyntax) {
self = "\(signature) {}"
public extension HasTrailingOptionalCodeBlock where Self: DeclSyntaxProtocol {
init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () -> CodeBlockItemListSyntax) throws {
let decl = DeclSyntax("\(header) {}")
guard let castedDecl = decl.as(Self.self) else {
throw SyntaxStringInterpolationError.producedInvalidNodeType(expectedType: Self.self, actualNode: decl)
}
self = castedDecl
self.body = CodeBlockSyntax(statements: bodyBuilder())
}
}
Expand All @@ -77,11 +94,17 @@ extension InitializerDeclSyntax: HasTrailingOptionalCodeBlock {}

public protocol HasTrailingMemberDeclBlock {
var members: MemberDeclBlockSyntax { get set }

init(_ header: PartialSyntaxNodeString, @MemberDeclListBuilder membersBuilder: () -> MemberDeclListSyntax) throws
}

public extension HasTrailingMemberDeclBlock where Self: SyntaxExpressibleByStringInterpolation {
init(_ signature: PartialSyntaxNodeString, @MemberDeclListBuilder membersBuilder: () -> MemberDeclListSyntax) {
self = "\(signature) {}"
public extension HasTrailingMemberDeclBlock where Self: DeclSyntaxProtocol {
init(_ header: PartialSyntaxNodeString, @MemberDeclListBuilder membersBuilder: () -> MemberDeclListSyntax) throws {
let decl = DeclSyntax("\(header) {}")
guard let castedDecl = decl.as(Self.self) else {
throw SyntaxStringInterpolationError.producedInvalidNodeType(expectedType: Self.self, actualNode: decl)
}
self = castedDecl
self.members = MemberDeclBlockSyntax(members: membersBuilder())
}
}
Expand All @@ -98,15 +121,23 @@ extension StructDeclSyntax: HasTrailingMemberDeclBlock {}
// So we cannot conform to `HasTrailingCodeBlock`

public extension IfStmtSyntax {
init(_ signature: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () -> CodeBlockItemListSyntax, @CodeBlockItemListBuilder `else` elseBuilder: () -> CodeBlockItemListSyntax? = { nil }) {
self = "\(signature) {}"
init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () -> CodeBlockItemListSyntax, @CodeBlockItemListBuilder `else` elseBuilder: () -> CodeBlockItemListSyntax? = { nil }) throws {
let stmt = StmtSyntax("\(header) {}")
guard let ifStmt = stmt.as(IfStmtSyntax.self) else {
throw SyntaxStringInterpolationError.producedInvalidNodeType(expectedType: Self.self, actualNode: stmt)
}
self = ifStmt
self.body = CodeBlockSyntax(statements: bodyBuilder())
self.elseBody = elseBuilder().map { .codeBlock(CodeBlockSyntax(statements: $0)) }
self.elseKeyword = elseBody != nil ? .keyword(.else) : nil
}

init(_ signature: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () -> CodeBlockItemListSyntax, elseIf: IfStmtSyntax) {
self = "\(signature) {}"
init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder bodyBuilder: () -> CodeBlockItemListSyntax, elseIf: IfStmtSyntax) throws {
let stmt = StmtSyntax("\(header) {}")
guard let ifStmt = stmt.as(IfStmtSyntax.self) else {
throw SyntaxStringInterpolationError.producedInvalidNodeType(expectedType: Self.self, actualNode: stmt)
}
self = ifStmt
self.body = CodeBlockSyntax(statements: bodyBuilder())
self.elseBody = .ifStmt(elseIf)
self.elseKeyword = elseBody != nil ? .keyword(.else) : nil
Expand All @@ -118,8 +149,12 @@ public extension IfStmtSyntax {
// So we cannot conform to `HasTrailingCodeBlock` or `HasTrailingMemberDeclBlock`

public extension SwitchStmtSyntax {
init(_ signature: PartialSyntaxNodeString, @SwitchCaseListBuilder casesBuilder: () -> SwitchCaseListSyntax = { SwitchCaseListSyntax([]) }) {
self = "\(signature) {}"
init(_ header: PartialSyntaxNodeString, @SwitchCaseListBuilder casesBuilder: () -> SwitchCaseListSyntax = { SwitchCaseListSyntax([]) }) throws {
let stmt = StmtSyntax("\(header) {}")
guard let castedStmt = stmt.as(Self.self) else {
throw SyntaxStringInterpolationError.producedInvalidNodeType(expectedType: Self.self, actualNode: stmt)
}
self = castedStmt
self.cases = casesBuilder()
}
}
Expand All @@ -129,8 +164,12 @@ public extension SwitchStmtSyntax {
// So we cannot conform to `HasTrailingCodeBlock` or `HasTrailingMemberDeclBlock`

public extension VariableDeclSyntax {
init(_ signature: PartialSyntaxNodeString, @CodeBlockItemListBuilder accessor: () -> CodeBlockItemListSyntax) {
self = "\(signature) {}"
init(_ header: PartialSyntaxNodeString, @CodeBlockItemListBuilder accessor: () -> CodeBlockItemListSyntax) throws {
let decl = DeclSyntax("\(header) {}")
guard let castedDecl = decl.as(Self.self) else {
throw SyntaxStringInterpolationError.producedInvalidNodeType(expectedType: Self.self, actualNode: decl)
}
self = castedDecl
assert(self.bindings.count == 1)
var binding: PatternBindingSyntax? = self.bindings.last
binding?.accessor = .getter(CodeBlockSyntax(statements: accessor()))
Expand Down
Loading